feat: 完成分享、单会话与发布审批改造

- 增加工作流协作分享与知识库卡片分享入口,统一低版本浏览器复制反馈

- Web 新登录替换旧会话,并保持 API Key 会话隔离

- 发布审批增加必填说明并在审批详情展示

- 账号重置与导入改用可配置默认强密码
This commit is contained in:
2026-07-23 16:09:31 +08:00
parent caa1f07b66
commit 5a42826d44
71 changed files with 3191 additions and 132 deletions

View File

@@ -0,0 +1,88 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { confirmPublishSubmission } from './approval-application-reason';
const { confirm, prompt } = vi.hoisted(() => ({
confirm: vi.fn(),
prompt: vi.fn(),
}));
vi.mock('element-plus', () => ({
ElMessageBox: {
confirm,
prompt,
},
}));
vi.mock('#/locales', () => ({
$t: (key: string) => key,
}));
describe('confirmPublishSubmission', () => {
const api = {
get: vi.fn(),
};
beforeEach(() => {
vi.clearAllMocks();
});
it('uses the normal confirmation when no approval flow matches', async () => {
api.get.mockResolvedValue({ data: false, errorCode: 0 });
confirm.mockResolvedValue('confirm');
await expect(
confirmPublishSubmission({
api,
confirmMessage: '确认发布?',
id: '1',
resourcePath: '/api/v1/workflow',
title: '提示',
}),
).resolves.toEqual({});
expect(confirm).toHaveBeenCalled();
expect(prompt).not.toHaveBeenCalled();
});
it('requires and trims a reason when an approval flow matches', async () => {
api.get.mockResolvedValue({ data: true, errorCode: 0 });
prompt.mockResolvedValue({ value: ' 本次修复复制兼容问题 ' });
await expect(
confirmPublishSubmission({
api,
confirmMessage: '确认提交发布审批?',
id: '1',
resourcePath: '/api/v1/workflow',
title: '提示',
}),
).resolves.toEqual({
applicationReason: '本次修复复制兼容问题',
});
const promptOptions = prompt.mock.calls[0]?.[2];
expect(promptOptions.inputValidator(' ')).toBe(
'approval.message.applicationReasonRequired',
);
expect(promptOptions.inputValidator('a'.repeat(501))).toBe(
'approval.message.applicationReasonTooLong',
);
expect(promptOptions.inputValidator('有效说明')).toBe(true);
});
it('returns null when the user cancels', async () => {
api.get.mockResolvedValue({ data: true, errorCode: 0 });
prompt.mockRejectedValue(new Error('cancel'));
await expect(
confirmPublishSubmission({
api,
confirmMessage: '确认提交发布审批?',
id: '1',
resourcePath: '/api/v1/workflow',
title: '提示',
}),
).resolves.toBeNull();
});
});

View File

@@ -0,0 +1,75 @@
import { ElMessageBox } from 'element-plus';
import { $t } from '#/locales';
type ApprovalRequirementApi = {
get: (
url: string,
config: { params: { id: number | string } },
) => Promise<{ data?: boolean; errorCode?: number }>;
};
type ConfirmPublishOptions = {
api: ApprovalRequirementApi;
confirmMessage: string;
id: number | string;
resourcePath: string;
title: string;
};
export type PublishConfirmation = {
applicationReason?: string;
};
/**
* 预检发布审批并完成相应的确认交互。
*
* @param options 发布确认参数
* @returns 用户取消时返回 null否则返回提交参数
*/
export async function confirmPublishSubmission(
options: ConfirmPublishOptions,
): Promise<null | PublishConfirmation> {
const response = await options.api.get(
`${options.resourcePath}/publishApprovalRequirement`,
{
params: { id: options.id },
},
);
try {
if (!response.data) {
await ElMessageBox.confirm(options.confirmMessage, options.title, {
cancelButtonText: $t('button.cancel'),
confirmButtonText: $t('button.confirm'),
type: 'info',
});
return {};
}
const { value } = await ElMessageBox.prompt(
$t('approval.message.applicationReasonPrompt'),
options.title,
{
cancelButtonText: $t('button.cancel'),
confirmButtonText: $t('approval.action.submit'),
inputPlaceholder: $t('approval.placeholder.applicationReason'),
inputType: 'textarea',
inputValidator: (input: string) => {
const normalized = String(input || '').trim();
if (!normalized) {
return $t('approval.message.applicationReasonRequired');
}
if (normalized.length > 500) {
return $t('approval.message.applicationReasonTooLong');
}
return true;
},
type: 'info',
},
);
return {
applicationReason: String(value || '').trim(),
};
} catch {
return null;
}
}