mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: 收到站内消息是增加提醒 (#86)
This commit is contained in:
1 parent
fb47598c57
commit
6cae5cb7d1
10 files changed
+62
-67
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.21.5",
|
"version": "2.21.6",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"typings": "dist/loader.d.ts",
|
"typings": "dist/loader.d.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
/* eslint-disable no-eval */
|
/* eslint-disable no-eval */
|
||||||
import fs from 'fs';
|
import fs from 'fs-extra';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
@@ -130,9 +130,7 @@ export async function template(pending: string[], fail: string[]) {
|
|||||||
try {
|
try {
|
||||||
const files = getFiles(p);
|
const files = getFiles(p);
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
global.Hydro.ui.template[file] = fs.readFileSync(
|
global.Hydro.ui.template[file] = await fs.readFile(path.resolve(p, file), 'utf-8');
|
||||||
path.resolve(p, file),
|
|
||||||
).toString();
|
|
||||||
}
|
}
|
||||||
logger.info('Template init: %s', i);
|
logger.info('Template init: %s', i);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -216,7 +214,7 @@ export async function service(pending: string[], fail: string[]) {
|
|||||||
export async function script(pending: string[], fail: string[], active: string[]) {
|
export async function script(pending: string[], fail: string[], active: string[]) {
|
||||||
for (const i of pending) {
|
for (const i of pending) {
|
||||||
const p = path.resolve(i, 'script.js');
|
const p = path.resolve(i, 'script.js');
|
||||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
if (await fs.pathExists(p) && !fail.includes(i)) {
|
||||||
try {
|
try {
|
||||||
logger.info('Script init: %s', i);
|
logger.info('Script init: %s', i);
|
||||||
eval('require')(p);
|
eval('require')(p);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
||||||
NotFoundError, UserNotFoundError, PermissionError, DomainAlreadyExistsError,
|
NotFoundError, UserNotFoundError, PermissionError, DomainAlreadyExistsError,
|
||||||
} from '../error';
|
} from '../error';
|
||||||
|
import { Mdoc } from '../interface';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import {
|
import {
|
||||||
Route, Connection, Handler, ConnectionHandler, param, Types,
|
Route, Connection, Handler, ConnectionHandler, param, Types,
|
||||||
@@ -328,6 +329,7 @@ class HomeMessagesHandler extends Handler {
|
|||||||
['Hydro', 'homepage'],
|
['Hydro', 'homepage'],
|
||||||
['home_messages', null],
|
['home_messages', null],
|
||||||
];
|
];
|
||||||
|
await user.setById(this.user._id, { unreadMsg: 0 });
|
||||||
this.response.body = { messages: parsed, path };
|
this.response.body = { messages: parsed, path };
|
||||||
this.response.template = 'home_messages.html';
|
this.response.template = 'home_messages.html';
|
||||||
}
|
}
|
||||||
@@ -367,9 +369,11 @@ class HomeMessagesConnectionHandler extends ConnectionHandler {
|
|||||||
this.dispose = bus.on('user/message', this.onMessageReceived.bind(this));
|
this.dispose = bus.on('user/message', this.onMessageReceived.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
async onMessageReceived(uid: number, e: any) {
|
async onMessageReceived(uid: number, mdoc: Mdoc) {
|
||||||
if (uid !== this.user._id) return;
|
if (uid !== this.user._id) return;
|
||||||
this.send(e);
|
const udoc = await user.getById(this.domainId, mdoc.from);
|
||||||
|
udoc.gravatar_url = misc.gravatar(udoc.gravatar, 64);
|
||||||
|
this.send({ udoc, mdoc });
|
||||||
}
|
}
|
||||||
|
|
||||||
async cleanup() {
|
async cleanup() {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class MessageModel {
|
|||||||
const udoc = await user.getById('system', to);
|
const udoc = await user.getById('system', to);
|
||||||
bus.boardcast('user/message', to, mdoc, udoc);
|
bus.boardcast('user/message', to, mdoc, udoc);
|
||||||
}
|
}
|
||||||
|
await user.inc(to, 'unreadMsg', 1);
|
||||||
return mdoc;
|
return mdoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ AccountSetting(
|
|||||||
Setting('setting_customize', 'backgroundImage',
|
Setting('setting_customize', 'backgroundImage',
|
||||||
'/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
'/components/profile/backgrounds/1.jpg', 'text', 'Profile Background Image',
|
||||||
'Choose the background image in your profile page.'),
|
'Choose the background image in your profile page.'),
|
||||||
Setting('setting_storage', 'usage', 0, 'number', 'Userfile Usage', null, FLAG_DISABLED | FLAG_HIDDEN),
|
Setting('setting_storage', 'unreadMsg', 0, 'number', 'Unread Message Count', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||||
Setting('setting_storage', 'checkincnt', 0, 'number', 'Check In Counter', null, FLAG_DISABLED | FLAG_HIDDEN),
|
Setting('setting_storage', 'checkincnt', 0, 'number', 'Check In Counter', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||||
Setting('setting_storage', 'lastcheckin', 0, 'number', 'Last checkin time', null, FLAG_DISABLED | FLAG_HIDDEN),
|
Setting('setting_storage', 'lastcheckin', 0, 'number', 'Last checkin time', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ export async function parallel<K extends keyof EventMap>(name: K, ...args: Param
|
|||||||
const tasks: Promise<any>[] = [];
|
const tasks: Promise<any>[] = [];
|
||||||
if (argv.showBus) logger.debug('parallel: %s %o', name, args);
|
if (argv.showBus) logger.debug('parallel: %s %o', name, args);
|
||||||
for (const callback of _hooks[name] || []) {
|
for (const callback of _hooks[name] || []) {
|
||||||
|
if (argv.busDetail) logger.debug(callback.toString());
|
||||||
tasks.push(callback.apply(this, args));
|
tasks.push(callback.apply(this, args));
|
||||||
}
|
}
|
||||||
await Promise.all(tasks);
|
await Promise.all(tasks);
|
||||||
|
|||||||
@@ -7,27 +7,38 @@ import tpl from 'vj/utils/tpl';
|
|||||||
|
|
||||||
const messagePage = new AutoloadPage('messagePage', () => {
|
const messagePage = new AutoloadPage('messagePage', () => {
|
||||||
async function init() {
|
async function init() {
|
||||||
|
if (UserContext.unreadMsg) {
|
||||||
|
new Notification({
|
||||||
|
type: 'info',
|
||||||
|
message: i18n('You have mew message.'),
|
||||||
|
action: () => window.open('/home/messages', '_blank'),
|
||||||
|
}).show();
|
||||||
|
}
|
||||||
|
|
||||||
const { default: SockJs } = await import('../socket');
|
const { default: SockJs } = await import('../socket');
|
||||||
|
|
||||||
const sock = new SockJs('/home/messages-conn');
|
const sock = new SockJs('/home/messages-conn');
|
||||||
sock.onmessage = (message) => {
|
sock.onmessage = (message) => {
|
||||||
const msg = JSON.parse(message.data);
|
const msg = JSON.parse(message.data);
|
||||||
if (msg.mdoc.flag | FLAG_ALERT) {
|
console.log('Received message', msg);
|
||||||
|
if (msg.mdoc.flag & FLAG_ALERT) {
|
||||||
// Is alert
|
// Is alert
|
||||||
const dialog = new InfoDialog({
|
new InfoDialog({
|
||||||
$body: tpl`
|
$body: tpl`
|
||||||
<div class="typo">
|
<div class="typo">
|
||||||
<p>${i18n(msg.udoc.content)}</p>
|
<p>${i18n('Message from {0}:', msg.mdoc.from)}</p>
|
||||||
|
<p>${i18n(msg.mdoc.content)}</p>
|
||||||
</div>`,
|
</div>`,
|
||||||
});
|
}).open();
|
||||||
dialog.open();
|
|
||||||
} else {
|
} else {
|
||||||
// Is message
|
// Is message
|
||||||
Notification.show({
|
new Notification({
|
||||||
title: msg.udoc.uname,
|
title: msg.udoc.uname,
|
||||||
avatar: msg.udoc.gravatar,
|
avatar: msg.udoc.gravatar_url,
|
||||||
message: msg.mdoc.content,
|
message: msg.mdoc.content,
|
||||||
});
|
duration: 15000,
|
||||||
|
action: () => window.open(`/home/messages?uid=${msg.udoc._id}`, '_blank'),
|
||||||
|
}).show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import tpl from 'vj/utils/tpl';
|
import tpl from 'vj/utils/tpl';
|
||||||
import zIndexManager from 'vj/utils/zIndexManager';
|
import zIndexManager from 'vj/utils/zIndexManager';
|
||||||
|
|
||||||
let lastNotification = null;
|
|
||||||
let autoHideTimer = null;
|
|
||||||
|
|
||||||
export default class Notification {
|
export default class Notification {
|
||||||
constructor({
|
constructor({
|
||||||
avatar, title, message, type = '', duration = 3000, action,
|
avatar, title, message, type = '', duration = 3000, action,
|
||||||
@@ -11,78 +8,48 @@ export default class Notification {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
if (avatar) this.type += ' avatar';
|
if (avatar) this.type += ' avatar';
|
||||||
if (title) this.type += ' title';
|
if (title) this.type += ' title';
|
||||||
this.action = (() => { }) || action;
|
this.action = action || (() => { });
|
||||||
this.$dom = $(tpl`<div class="notification ${type} hide"></div>`);
|
this.$dom = $(tpl`<div class="notification ${type} hide"></div>`);
|
||||||
if (avatar) $(tpl`<img width="64" height="64" class="avatar" src="${avatar}"></img>`).appendTo(this.$dom);
|
if (avatar) $(tpl`<img width="64" height="64" class="avatar" src="${avatar}"></img>`).appendTo(this.$dom);
|
||||||
if (title) $(tpl`<h2>${title}</h2>`).appendTo(this.$dom);
|
if (title) {
|
||||||
$(tpl`<p>${message}</p>`).appendTo(this.$dom);
|
$(tpl`<div class="notification-content"><h2>${title}</h2><p>${message}</p></div>`).appendTo(this.$dom);
|
||||||
this.$dom.on('clink', this.handleClick.bind(this));
|
} else $(tpl`<p>${message}</p>`).appendTo(this.$dom);
|
||||||
|
this.$dom.on('click', this.handleClick.bind(this));
|
||||||
this.$n = this.$dom
|
this.$n = this.$dom
|
||||||
.css('z-index', zIndexManager.getNext())
|
.css('z-index', zIndexManager.getNext())
|
||||||
.appendTo('body');
|
.appendTo(document.body);
|
||||||
this.$n.width(); // force reflow
|
this.$n.width(); // force reflow
|
||||||
this.$n.removeClass('hide');
|
this.duration = duration;
|
||||||
if (duration) this.autoHideTimer = setTimeout(this.hide.bind(this), duration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick() {
|
handleClick() {
|
||||||
this.action();
|
this.action();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
show(autohide = true) {
|
||||||
|
this.$n.removeClass('hide');
|
||||||
|
if (this.duration && autohide) this.autoHideTimer = setTimeout(this.hide.bind(this), this.duration);
|
||||||
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
this.$n.addClass('hide');
|
this.$n.addClass('hide');
|
||||||
setTimeout(() => this.$n.remove(), 200);
|
setTimeout(() => this.$n.remove(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
static success(message, duration) {
|
static success(message, duration) {
|
||||||
return Notification.show({ type: 'success', message, duration });
|
return new Notification({ type: 'success', message, duration }).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
static info(message, duration) {
|
static info(message, duration) {
|
||||||
return Notification.show({ type: 'info', message, duration });
|
return new Notification({ type: 'info', message, duration }).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
static warn(message, duration) {
|
static warn(message, duration) {
|
||||||
return Notification.show({ type: 'warn', message, duration });
|
return new Notification({ type: 'warn', message, duration }).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
static error(message, duration) {
|
static error(message, duration) {
|
||||||
return Notification.show({ type: 'error', message, duration });
|
return new Notification({ type: 'error', message, duration }).show();
|
||||||
}
|
|
||||||
|
|
||||||
static show({
|
|
||||||
avatar, title, message, type = '', duration = 3000, action,
|
|
||||||
}) {
|
|
||||||
if (lastNotification) Notification.hide();
|
|
||||||
if (avatar) type += ' avatar';
|
|
||||||
if (title) type += ' title';
|
|
||||||
const $dom = $(tpl`<div class="notification ${type} hide"></div>`);
|
|
||||||
if (avatar) $(tpl`<img width="64" height="64" class="avatar" src="${avatar}"></img>`).appendTo($dom);
|
|
||||||
if (title) $(tpl`<h2>${title}</h2>`).appendTo($dom);
|
|
||||||
$(tpl`<p>${message}</p>`).appendTo($dom);
|
|
||||||
$dom.on('clink', action);
|
|
||||||
const $n = $dom
|
|
||||||
.css('z-index', zIndexManager.getNext())
|
|
||||||
.appendTo('body');
|
|
||||||
$n.width(); // force reflow
|
|
||||||
$n.removeClass('hide');
|
|
||||||
lastNotification = $n;
|
|
||||||
autoHideTimer = setTimeout(Notification.hide, duration);
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static hide() {
|
|
||||||
if (!lastNotification) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (autoHideTimer) {
|
|
||||||
clearTimeout(autoHideTimer);
|
|
||||||
autoHideTimer = null;
|
|
||||||
}
|
|
||||||
const $n = lastNotification;
|
|
||||||
$n.addClass('hide');
|
|
||||||
setTimeout(() => $n.remove(), 200);
|
|
||||||
lastNotification = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,3 +47,16 @@
|
|||||||
width: 100%
|
width: 100%
|
||||||
min-width: auto
|
min-width: auto
|
||||||
bottom: 0
|
bottom: 0
|
||||||
|
|
||||||
|
.notification-content
|
||||||
|
float: right
|
||||||
|
margin-top: rem(7px)
|
||||||
|
margin-left: rem(10px)
|
||||||
|
margin-right: rem(15px)
|
||||||
|
|
||||||
|
h2
|
||||||
|
color: #FFFFFF
|
||||||
|
|
||||||
|
p
|
||||||
|
margin-top: rem(7px);
|
||||||
|
font-size: larger
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hydrooj/ui-default",
|
"name": "@hydrooj/ui-default",
|
||||||
"version": "4.5.4",
|
"version": "4.5.5",
|
||||||
"author": "undefined <i@undefined.moe>",
|
"author": "undefined <i@undefined.moe>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"main": "hydro.js",
|
"main": "hydro.js",
|
||||||
|
|||||||
Reference in new issue
Block a user