Compare commits

...

8 Commits

Author SHA1 Message Date
CrescentLeaf
62ee2ef01f feat(wip): 帐号设定 2025-10-26 15:16:29 +08:00
CrescentLeaf
04125a1495 feat(wip): 重设密码 2025-10-26 15:16:20 +08:00
CrescentLeaf
110a90ed7a feat: 重连服务器提示 2025-10-26 15:13:40 +08:00
CrescentLeaf
bfc14777be feat: 检验是否能请求加入对话 2025-10-26 14:24:26 +08:00
CrescentLeaf
4e34e70a11 feat: 手动刷新对话页面 2025-10-26 14:24:06 +08:00
CrescentLeaf
2d2bc7be83 ui: 请求加入对话的组件状态跟随群组设定 2025-10-26 14:23:56 +08:00
CrescentLeaf
5d6c4d6660 fix: 错误的使用 admin 表名, 应为 getJoinRequestsTableName 2025-10-26 14:19:05 +08:00
CrescentLeaf
ab8895b008 fix: 退出登录失败 2025-10-26 14:04:07 +08:00
8 changed files with 88 additions and 10 deletions

View File

@@ -7,6 +7,7 @@ export type CallMethod =
"User.setAvatar" |
"User.updateProfile" |
"User.getMyInfo" |
"User.resetPassword" |
"User.getInfo" |

View File

@@ -3,7 +3,7 @@ import { CallMethod, ClientEvent, CallableMethodBeforeAuth } from './ApiDeclare.
import ApiCallbackMessage from './ApiCallbackMessage.ts'
import User from "./client_data/User.ts"
import data from "../Data.ts"
import { checkApiSuccessOrSncakbar } from "../ui/snackbar.ts"
import { checkApiSuccessOrSncakbar, snackbar } from "../ui/snackbar.ts"
import randomUUID from "../randomUUID.ts"
class Client {
@@ -32,6 +32,21 @@ class Client {
})
this.socket!.on("disconnect", () => {
this.connected = false
const s = snackbar({
message: '重新连接服务器中...',
placement: 'top',
autoCloseDelay: 0,
})
let i = 1
const id = setInterval(() => {
s.textContent = `重新连接服务器中... (${i}s)`
i++
this.socket!.connect()
}, 1000)
this.socket!.once('connect', () => {
s.open = false
clearTimeout(id)
})
})
this.socket!.on("The_White_Silk", (name: string, data: unknown, callback: (ret: unknown) => void) => {
try {

View File

@@ -78,7 +78,9 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
tabRef.current != null && setTabItemSelected(tabRef.current!.value as string)
})
useAsyncEffect(async () => {
async function getChatInfoAndInit() {
setMessagesList([])
page.current = 0
const re = await Client.invoke('Chat.getInfo', {
token: data.access_token,
target: target,
@@ -101,7 +103,8 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
behavior: "smooth",
})
}, 300)
}, [target])
}
useAsyncEffect(getChatInfoAndInit, [target])
const page = React.useRef(0)
async function loadMore() {
@@ -222,6 +225,7 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
for (const file of files) {
addFile(file.type, file.name, file)
}
uploadChatAvatarRef.current!.value = ''
})
useEventListener(uploadChatAvatarRef, 'change', async (_e) => {
const file = uploadChatAvatarRef.current!.files?.[0] as File
@@ -232,6 +236,7 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
target: target,
avatar: file
})
uploadChatAvatarRef.current!.value = ''
if (checkApiSuccessOrSncakbar(re, "修改失败")) return
snackbar({
@@ -283,6 +288,11 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
<div style={{
flexGrow: '1',
}}></div>
<mdui-button-icon icon="refresh" onClick={() => getChatInfoAndInit()} style={{
alignSelf: 'center',
marginLeft: '5px',
marginRight: '5px',
}}></mdui-button-icon>
<mdui-button-icon icon="info" onClick={() => openChatInfoDialog(chatInfo)} style={{
alignSelf: 'center',
marginLeft: '5px',
@@ -297,7 +307,7 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
alignItems: 'center',
}}>
<div>
<mdui-button onClick={async () => {
<mdui-button disabled={!groupPreferenceStore.state.allow_new_member_join} onClick={async () => {
const re = await Client.invoke("Chat.sendJoinRequest", {
token: data.access_token,
target: target,

View File

@@ -65,9 +65,9 @@ export default function MyProfileDialog({
}}></mdui-divider>
<mdui-list>
<mdui-list-item icon="edit" rounded onClick={() => userProfileEditDialogRef.current!.open = true}></mdui-list-item>
<mdui-list-item icon="edit" rounded onClick={() => userProfileEditDialogRef.current!.open = true}></mdui-list-item>
<mdui-list-item icon="settings" rounded></mdui-list-item>
{/*
<mdui-list-item icon="settings" rounded>賬號設定</mdui-list-item>
<mdui-list-item icon="lock" rounded>隱私設定</mdui-list-item>
*/}
<mdui-divider style={{
@@ -87,6 +87,7 @@ export default function MyProfileDialog({
{
text: "确定",
onClick: () => {
data.refresh_token = ''
data.access_token = ''
data.apply()
location.reload()
@@ -97,6 +98,13 @@ export default function MyProfileDialog({
})}>退</mdui-list-item>
</mdui-list>
</mdui-dialog>
{
// 账号设定
}
<mdui-dialog close-on-overlay-click close-on-esc ref={userProfileEditDialogRef} headline="账号设定">
<mdui-button slot="action" variant="text" onClick={() => userProfileEditDialogRef.current!.open = false}></mdui-button>
</mdui-dialog>
{
// 個人資料編輯
}

View File

@@ -7,6 +7,7 @@ export type CallMethod =
"User.setAvatar" |
"User.updateProfile" |
"User.getMyInfo" |
"User.resetPassword" |
"User.getInfo" |

View File

@@ -283,8 +283,16 @@ export default class ChatApi extends BaseApi {
code: 404,
msg: "对话不存在",
}
chat.addJoinRequest(token.author, args.reason as string)
if (chat.bean.type == 'group') {
const settings = ChatGroup.fromChat(chat).getSettings()
if (settings.settings.allow_new_member_join)
chat.addJoinRequest(token.author, args.reason as string)
else
return {
code: 403,
msg: "该对话不允许加入请求",
}
}
return {
code: 200,

View File

@@ -79,7 +79,7 @@ export default class UserApi extends BaseApi {
msg: "验证失败",
code: 401,
}
const user = User.findById(refresh_token.author) as User
return {
@@ -156,6 +156,41 @@ export default class UserApi extends BaseApi {
},
}
})
// 登錄
this.registerEvent("User.resetPassword", (args, { deviceId }) => {
if (this.checkArgsMissing(args, ['token', 'old_password', 'new_password'])) return {
msg: "参数缺失",
code: 400,
}
if (this.checkArgsEmpty(args, ['token', 'old_password', 'new_password'])) return {
msg: "参数不得为空",
code: 400,
}
const token = TokenManager.decode(args.token as string)
if (!this.checkToken(token, deviceId)) return {
code: 401,
msg: "令牌无效",
}
const user = User.findById(token.author) as User
if (user.getPassword() == args.old_password) {
user.setPassword(args.new_password as string)
return {
msg: "成功",
code: 200,
data: {
refresh_token: TokenManager.make(user, null, deviceId, 'refresh_token'),
access_token: TokenManager.make(user, null, deviceId),
},
}
}
return {
msg: "账号或密码错误",
code: 400,
}
})
/*
* ================================================
* 個人資料

View File

@@ -137,7 +137,7 @@ export default class Chat {
return Chat.database.prepare(`SELECT * FROM ${this.getJoinRequestsTableName()}`).all()
}
protected findAllJoinRequestsByCondition(condition: string, ...args: SQLInputValue[]) {
return Chat.database.prepare(`SELECT * FROM ${this.getAdminsTableName()} WHERE ${condition}`).all(...args)
return Chat.database.prepare(`SELECT * FROM ${this.getJoinRequestsTableName()} WHERE ${condition}`).all(...args)
}
/**