feat(v3.4.13): partner column, version release cascade, client UX fixes
- HQ stores: partner column uses companyName/name/phone via partnerOptionLabel - Dev plan: version RELEASED auto-marks tasks RELEASED and tickets PUBLISHED with releasedVersionNo - mini-user/h5-shop/h5-partner v3.4.13 UX fixes (store UI, iOS scan OAuth, partner login guard) - Docs: v3.4.13 dev doc + status audit updates Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,6 +29,15 @@ describe('validateSupportTicketStatusTransition', () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('allows PASSED -> PUBLISHED', () => {
|
||||
expect(
|
||||
validateSupportTicketStatusTransition('PASSED', 'PUBLISHED', {
|
||||
linkedTaskCount: 1,
|
||||
isSuperAdmin: true,
|
||||
}).ok,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('requires super admin and reason for REJECTED', () => {
|
||||
expect(
|
||||
validateSupportTicketStatusTransition('DEVELOPING', 'REJECTED', {
|
||||
|
||||
@@ -3,7 +3,8 @@ export type SupportTicketStatus =
|
||||
| 'REJECTED'
|
||||
| 'DEVELOPING'
|
||||
| 'TESTING'
|
||||
| 'PASSED';
|
||||
| 'PASSED'
|
||||
| 'PUBLISHED';
|
||||
|
||||
export type SupportTicketStatusTransitionContext = {
|
||||
linkedTaskCount: number;
|
||||
@@ -16,7 +17,8 @@ const FORWARD_TRANSITIONS: Record<SupportTicketStatus, SupportTicketStatus[]> =
|
||||
DEVELOPING: ['TESTING', 'REJECTED'],
|
||||
TESTING: ['PASSED', 'REJECTED'],
|
||||
REJECTED: [],
|
||||
PASSED: [],
|
||||
PASSED: ['PUBLISHED'],
|
||||
PUBLISHED: [],
|
||||
};
|
||||
|
||||
/** 技术支持工单批量/人工改状态校验(禁止回退) */
|
||||
|
||||
@@ -15,7 +15,8 @@ export type SupportTicketStatusDto =
|
||||
| 'REJECTED'
|
||||
| 'DEVELOPING'
|
||||
| 'TESTING'
|
||||
| 'PASSED';
|
||||
| 'PASSED'
|
||||
| 'PUBLISHED';
|
||||
|
||||
export const SUPPORT_TICKET_STATUSES = [
|
||||
'PENDING_REVIEW',
|
||||
@@ -23,6 +24,7 @@ export const SUPPORT_TICKET_STATUSES = [
|
||||
'DEVELOPING',
|
||||
'TESTING',
|
||||
'PASSED',
|
||||
'PUBLISHED',
|
||||
] as const;
|
||||
|
||||
export const SUPPORT_TICKET_STATUS_LABELS: Record<SupportTicketStatusDto, string> = {
|
||||
@@ -31,6 +33,7 @@ export const SUPPORT_TICKET_STATUS_LABELS: Record<SupportTicketStatusDto, string
|
||||
DEVELOPING: '开发',
|
||||
TESTING: '测试',
|
||||
PASSED: '通过',
|
||||
PUBLISHED: '已发布',
|
||||
};
|
||||
|
||||
/** 技术支持工单优先级 */
|
||||
@@ -64,6 +67,8 @@ export interface SupportTicketDto {
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
completedAt?: string | null;
|
||||
releasedVersionNo?: string | null;
|
||||
publishedAt?: string | null;
|
||||
}
|
||||
|
||||
export interface CreateSupportTicketRequest {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export { isWechatBrowser, isMiniProgram, getRuntimePlatform } from './env';
|
||||
export { isWechatBrowser, isMiniProgram, getRuntimePlatform, isIosDevice, isWechatDevTools } from './env';
|
||||
export { getRouterBasename, toAppPath, isOnAppPath } from './app-path';
|
||||
export {
|
||||
initWechatJssdk,
|
||||
@@ -10,7 +10,7 @@ export {
|
||||
resetJssdkConfig,
|
||||
stripOAuthParamsFromLocation,
|
||||
} from './jssdk';
|
||||
export { formatScanFailMessage } from './scan';
|
||||
export { formatScanFailMessage, isScanPermissionWarmupError } from './scan';
|
||||
export {
|
||||
getWechatLocation,
|
||||
getWechatLocationDetailed,
|
||||
|
||||
@@ -38,7 +38,7 @@ export function formatScanFailMessage(errMsg: string): string {
|
||||
return msg;
|
||||
}
|
||||
|
||||
function isScanPermissionWarmupError(msg: string): boolean {
|
||||
export function isScanPermissionWarmupError(msg: string): boolean {
|
||||
return /offline verifying|permission value is offline|权限验证中|接口未就绪|invalid signature|config:fail|signature/i.test(
|
||||
msg,
|
||||
);
|
||||
@@ -134,15 +134,13 @@ export async function scanQrCode(
|
||||
throw new Error('当前微信版本不支持扫码,请升级微信后重试');
|
||||
}
|
||||
|
||||
// wx.ready ≠ 权限离线校验完成;授权回跳后更明显
|
||||
const warmupMs = options.postAuthWarmup
|
||||
? 1200
|
||||
: isIosDevice() && !isWechatDevTools()
|
||||
? 800
|
||||
: 300;
|
||||
const ios = isIosDevice() && !isWechatDevTools();
|
||||
|
||||
// wx.ready ≠ 权限离线校验完成;OAuth 回跳后 iOS 更明显
|
||||
const warmupMs = options.postAuthWarmup ? (ios ? 1600 : 1000) : ios ? 800 : 300;
|
||||
await delay(warmupMs);
|
||||
|
||||
const maxAttempts = options.postAuthWarmup ? 3 : 2;
|
||||
const maxAttempts = options.postAuthWarmup ? (ios ? 4 : 3) : 2;
|
||||
let lastError: Error | null = null;
|
||||
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
||||
if (attempt > 0) {
|
||||
@@ -151,7 +149,8 @@ export async function scanQrCode(
|
||||
await initWechatJssdk({ ...jssdkOptions, url: getJssdkSignUrl() });
|
||||
await checkJsApi('scanQRCode');
|
||||
}
|
||||
await delay(700 + attempt * 500);
|
||||
const retryDelay = options.postAuthWarmup && ios ? 900 + attempt * 700 : 700 + attempt * 500;
|
||||
await delay(retryDelay);
|
||||
}
|
||||
try {
|
||||
return await invokeScanQrCode();
|
||||
|
||||
Reference in New Issue
Block a user