接入 ESLint 并清理未使用代码
- 前后端接入 ESLint 10 扁平配置(typescript-eslint 类型感知检查 + react-hooks/react-refresh),新增 lint / lint:check / lint:fix 脚本并纳入 check 链路 - 清理全部 no-unused-vars 与 no-useless-assignment 警告,修复 floating promises、正则转义等问题 - 删除确认无引用的死代码(markKuaishouCloudBindUrlRefreshFailed、未使用 helper 等)
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
import eslint from '@eslint/js'
|
||||||
|
import globals from 'globals'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{
|
||||||
|
ignores: ['dist/**', 'node_modules/**', 'data/**'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['src/**/*.ts', 'scripts/**/*.ts'],
|
||||||
|
extends: [eslint.configs.recommended, ...tseslint.configs.recommended],
|
||||||
|
languageOptions: {
|
||||||
|
globals: globals.node,
|
||||||
|
parserOptions: {
|
||||||
|
project: './tsconfig.eslint.json',
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-floating-promises': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignoreIIFE: true,
|
||||||
|
ignoreVoid: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-misused-promises': 'error',
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
caughtErrorsIgnorePattern: '^_',
|
||||||
|
destructuredArrayIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'no-useless-assignment': 'warn',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['src/**/*.test.ts'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-floating-promises': 'off',
|
||||||
|
'no-control-regex': 'off',
|
||||||
|
'no-regex-spaces': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
Generated
+1085
-1
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,11 @@
|
|||||||
"db:migrate:create": "tsx scripts/create-migration.ts",
|
"db:migrate:create": "tsx scripts/create-migration.ts",
|
||||||
"db:migrate:status": "tsx scripts/migration-status.ts",
|
"db:migrate:status": "tsx scripts/migration-status.ts",
|
||||||
"dev": "tsx watch --clear-screen=false src/index.ts",
|
"dev": "tsx watch --clear-screen=false src/index.ts",
|
||||||
"format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write \"src/**/*.{ts,js,json}\" \"scripts/**/*.{ts,js}\" package.json tsconfig.json tsconfig.build.json",
|
"format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write \"src/**/*.{ts,js,json}\" \"scripts/**/*.{ts,js}\" eslint.config.js package.json tsconfig.json tsconfig.build.json tsconfig.eslint.json",
|
||||||
"format:check": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check \"src/**/*.{ts,js,json}\" \"scripts/**/*.{ts,js}\" package.json tsconfig.json tsconfig.build.json",
|
"format:check": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check \"src/**/*.{ts,js,json}\" \"scripts/**/*.{ts,js}\" eslint.config.js package.json tsconfig.json tsconfig.build.json tsconfig.eslint.json",
|
||||||
|
"lint": "eslint \"src/**/*.ts\" \"scripts/**/*.ts\"",
|
||||||
|
"lint:check": "npm run lint -- --quiet",
|
||||||
|
"lint:fix": "npm run lint -- --fix",
|
||||||
"mock:claim": "tsx scripts/mock-kuaishou-cloud-claim.ts",
|
"mock:claim": "tsx scripts/mock-kuaishou-cloud-claim.ts",
|
||||||
"mock:open91": "tsx scripts/mock-open91-order.ts",
|
"mock:open91": "tsx scripts/mock-open91-order.ts",
|
||||||
"test": "node --import tsx --test $(find src \\( -name '*.test.ts' -o -name '*.test.js' \\) -print)",
|
"test": "node --import tsx --test $(find src \\( -name '*.test.ts' -o -name '*.test.js' \\) -print)",
|
||||||
@@ -20,7 +23,7 @@
|
|||||||
"test:industry:gen": "tsx scripts/gen-test-cases.ts",
|
"test:industry:gen": "tsx scripts/gen-test-cases.ts",
|
||||||
"test:industry:curl": "tsx scripts/curl-send-callback.ts",
|
"test:industry:curl": "tsx scripts/curl-send-callback.ts",
|
||||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||||
"check": "npm run format:check && npm run typecheck && npm test && npm run build",
|
"check": "npm run format:check && npm run lint:check && npm run typecheck && npm test && npm run build",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"start:src": "tsx src/index.ts",
|
"start:src": "tsx src/index.ts",
|
||||||
"mock:feifei": "tsx scripts/mock-feifei-claim.ts"
|
"mock:feifei": "tsx scripts/mock-feifei-claim.ts"
|
||||||
@@ -37,12 +40,16 @@
|
|||||||
"sharp": "^0.35.3"
|
"sharp": "^0.35.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "10.0.1",
|
||||||
"@types/express": "^5.0.6",
|
"@types/express": "^5.0.6",
|
||||||
"@types/multer": "^2.2.0",
|
"@types/multer": "^2.2.0",
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/pg": "^8.20.0",
|
"@types/pg": "^8.20.0",
|
||||||
|
"eslint": "10.8.1",
|
||||||
|
"globals": "17.11.0",
|
||||||
"prettier": "3.8.3",
|
"prettier": "3.8.3",
|
||||||
"tsx": "^4.22.3",
|
"tsx": "^4.22.3",
|
||||||
"typescript": "^6.0.2"
|
"typescript": "^6.0.2",
|
||||||
|
"typescript-eslint": "8.67.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ async function call(endpoint: string, params: JsonObject) {
|
|||||||
|
|
||||||
const started = Date.now()
|
const started = Date.now()
|
||||||
let status = 0
|
let status = 0
|
||||||
let json: JsonObject = {}
|
let json: JsonObject
|
||||||
try {
|
try {
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -136,10 +136,6 @@ function paramsToForm(params: JsonObject): string {
|
|||||||
return p.join('&') + `¶m=${encodeURIComponent(String(params.param || '{}'))}` + signPart
|
return p.join('&') + `¶m=${encodeURIComponent(String(params.param || '{}'))}` + signPart
|
||||||
}
|
}
|
||||||
|
|
||||||
function pp(v: unknown): string {
|
|
||||||
return JSON.stringify(v, null, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ───── 先准备订单 ─────
|
// ───── 先准备订单 ─────
|
||||||
console.log('---')
|
console.log('---')
|
||||||
console.log('准备测试订单...\n')
|
console.log('准备测试订单...\n')
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ async function post(
|
|||||||
|
|
||||||
const startedAt = Date.now()
|
const startedAt = Date.now()
|
||||||
let status = 0
|
let status = 0
|
||||||
let data: JsonObject = {}
|
let data: JsonObject
|
||||||
let ok = false
|
let ok = false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ export function resolveInitialPaidTaskStatus(
|
|||||||
| null
|
| null
|
||||||
| undefined,
|
| undefined,
|
||||||
): TaskStatus {
|
): TaskStatus {
|
||||||
if (Boolean(profile?.requires_claim)) {
|
if (profile?.requires_claim) {
|
||||||
return TASK_STATUS.PAID
|
return TASK_STATUS.PAID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { TASK_STATUS } from '../domain/task-status.js'
|
|||||||
import { maskCode } from '../utils/masking.js'
|
import { maskCode } from '../utils/masking.js'
|
||||||
import { parseTaskContext } from '../utils/task-json.js'
|
import { parseTaskContext } from '../utils/task-json.js'
|
||||||
import { normalizeTimestampIso } from '../utils/time.js'
|
import { normalizeTimestampIso } from '../utils/time.js'
|
||||||
import type { JsonObject, JsonRecord } from '../types/json.js'
|
import type { JsonRecord } from '../types/json.js'
|
||||||
|
|
||||||
type QueryExecutor = (text: string, params?: unknown[]) => Promise<{ rows: unknown[] }>
|
type QueryExecutor = (text: string, params?: unknown[]) => Promise<{ rows: unknown[] }>
|
||||||
export type KuaishouCloudSourceLoadStat = {
|
export type KuaishouCloudSourceLoadStat = {
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ export async function verifyAdminSessionToken(token: unknown): Promise<AdminSess
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload: JsonObject | null = null
|
let payload: JsonObject | null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
payload = JSON.parse(Buffer.from(encodedPayload, 'base64url').toString('utf8'))
|
payload = JSON.parse(Buffer.from(encodedPayload, 'base64url').toString('utf8'))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { listOrderItemsByOrderId } from '../../repositories/order-item-repo.js'
|
|||||||
import { getOrderById, listOrders } from '../../repositories/order-repo.js'
|
import { getOrderById, listOrders } from '../../repositories/order-repo.js'
|
||||||
import { getTaskById, listTasks, listTasksByOrderId } from '../../repositories/task-repo.js'
|
import { getTaskById, listTasks, listTasksByOrderId } from '../../repositories/task-repo.js'
|
||||||
import { listTaskEventsByTaskId } from '../../repositories/task-event-repo.js'
|
import { listTaskEventsByTaskId } from '../../repositories/task-event-repo.js'
|
||||||
import type { JsonObject, JsonRecord } from '../../types/json.js'
|
import type { JsonRecord } from '../../types/json.js'
|
||||||
import {
|
import {
|
||||||
listKuaishouIndustryVouchersByOid,
|
listKuaishouIndustryVouchersByOid,
|
||||||
listKuaishouIndustryVouchersByTaskId,
|
listKuaishouIndustryVouchersByTaskId,
|
||||||
@@ -474,7 +474,7 @@ function buildCloudSourceLabelMap() {
|
|||||||
|
|
||||||
export async function getAdminTaskScreenshotPath(
|
export async function getAdminTaskScreenshotPath(
|
||||||
taskId: AdminEntityIdInput,
|
taskId: AdminEntityIdInput,
|
||||||
session: AdminViewerSessionInput | null = null,
|
_session: AdminViewerSessionInput | null = null,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const task = await getRequiredTask(taskId)
|
const task = await getRequiredTask(taskId)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { safeParseJson } from './admin-query-utils.js'
|
import { safeParseJson } from './admin-query-utils.js'
|
||||||
import { normalizeAdminRole } from './admin-auth-service.js'
|
import { normalizeAdminRole } from './admin-auth-service.js'
|
||||||
import { asJsonObject, type JsonObject, JsonRecord } from '../../types/json.js'
|
import { asJsonObject, type JsonRecord } from '../../types/json.js'
|
||||||
import {
|
import {
|
||||||
parseTaskContext as parseTaskContextValue,
|
parseTaskContext as parseTaskContextValue,
|
||||||
parseTaskState as parseTaskStateValue,
|
parseTaskState as parseTaskStateValue,
|
||||||
@@ -379,7 +379,7 @@ export function createAdminViewerContext(
|
|||||||
|
|
||||||
export async function resolveAdminTaskScreenshotUrl(
|
export async function resolveAdminTaskScreenshotUrl(
|
||||||
task: TaskLike,
|
task: TaskLike,
|
||||||
viewerContext: AdminViewerContext,
|
_viewerContext: AdminViewerContext,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (task.screenshot_path || task.runtime_session_id) {
|
if (task.screenshot_path || task.runtime_session_id) {
|
||||||
return `/api/v1/admin/tasks/${task.id}/screenshot`
|
return `/api/v1/admin/tasks/${task.id}/screenshot`
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { getTaskById } from '../../repositories/task-repo.js'
|
import { getTaskById } from '../../repositories/task-repo.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { safeParseJson } from './admin-query-utils.js'
|
import { safeParseJson } from './admin-query-utils.js'
|
||||||
import { asJsonObject, type JsonObject, JsonRecord } from '../../types/json.js'
|
import { asJsonObject, type JsonRecord } from '../../types/json.js'
|
||||||
import {
|
import {
|
||||||
TASK_STATUS,
|
TASK_STATUS,
|
||||||
isTaskFulfillmentCompletedStatus,
|
isTaskFulfillmentCompletedStatus,
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ export async function submitAffiliateDashClaim(
|
|||||||
const now = nowIso()
|
const now = nowIso()
|
||||||
const isMock = Boolean(flow.mock?.enabled)
|
const isMock = Boolean(flow.mock?.enabled)
|
||||||
const gameAccount = expectedGameAccount
|
const gameAccount = expectedGameAccount
|
||||||
let latestFlow = flow
|
const latestFlow = flow
|
||||||
|
|
||||||
if (!isMock && flow.bindUuid) {
|
if (!isMock && flow.bindUuid) {
|
||||||
// 提交前不再额外请求 bind-result:平台侧曾出现 GET 后 submit 的 bind_verify 异常。
|
// 提交前不再额外请求 bind-result:平台侧曾出现 GET 后 submit 的 bind_verify 异常。
|
||||||
|
|||||||
@@ -931,7 +931,6 @@ function buildLewanMockContext(input: {
|
|||||||
timestamp: string
|
timestamp: string
|
||||||
}) {
|
}) {
|
||||||
const roleReady = ['binding', 'confirm', 'result'].includes(input.step)
|
const roleReady = ['binding', 'confirm', 'result'].includes(input.step)
|
||||||
const roleConfirmed = ['confirm', 'result'].includes(input.step)
|
|
||||||
const completed = input.step === 'result'
|
const completed = input.step === 'result'
|
||||||
const boundUid = roleReady ? input.expectedUid || '10001' : ''
|
const boundUid = roleReady ? input.expectedUid || '10001' : ''
|
||||||
const primaryItem = input.deliveryItems[0] || {
|
const primaryItem = input.deliveryItems[0] || {
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ export async function syncAffiliateDashTaskStatus(
|
|||||||
let resultMessage = task.result_message
|
let resultMessage = task.result_message
|
||||||
let lastError = task.last_error
|
let lastError = task.last_error
|
||||||
const nextFlow = mergeAffiliateDashOrder(flow, order, { syncedAt: now })
|
const nextFlow = mergeAffiliateDashOrder(flow, order, { syncedAt: now })
|
||||||
let nextIndustryVoucher = taskContext.kuaishouIndustryVoucher
|
const nextIndustryVoucher = taskContext.kuaishouIndustryVoucher
|
||||||
|
|
||||||
switch (order.orderStatus) {
|
switch (order.orderStatus) {
|
||||||
case 'paid':
|
case 'paid':
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export async function selectCloudtentaclesSourceForFulfillment(
|
|||||||
const ranked = []
|
const ranked = []
|
||||||
let lastCapacityError: unknown = null
|
let lastCapacityError: unknown = null
|
||||||
for (const [index, context] of contexts.entries()) {
|
for (const [index, context] of contexts.entries()) {
|
||||||
let occupiedCount = 0
|
let occupiedCount
|
||||||
try {
|
try {
|
||||||
// CT's VN list is the authoritative count; DB counters can lag after crashes/restarts.
|
// CT's VN list is the authoritative count; DB counters can lag after crashes/restarts.
|
||||||
const listed = await listVirtualNumbers({
|
const listed = await listVirtualNumbers({
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export async function prepareKuaishouCloudBindResourceWithFallback(input: JsonOb
|
|||||||
|
|
||||||
for (const vnKey of candidates) {
|
for (const vnKey of candidates) {
|
||||||
let vnId = 0
|
let vnId = 0
|
||||||
let vnPhone = ''
|
let vnPhone
|
||||||
const cooldownKey = `${sourceKey}|${vnKey}`
|
const cooldownKey = `${sourceKey}|${vnKey}`
|
||||||
|
|
||||||
const cooldownUntil = appointQuotaCooldowns.get(cooldownKey) || 0
|
const cooldownUntil = appointQuotaCooldowns.get(cooldownKey) || 0
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import { createTaskEvent } from '../../../repositories/task-event-repo.js'
|
|
||||||
import { updateTask } from '../../../repositories/task-repo.js'
|
import { updateTask } from '../../../repositories/task-repo.js'
|
||||||
import { probeCloudtentaclesBindUrl } from '../../platforms/cloudtentacles/virtual-number-service.js'
|
import { probeCloudtentaclesBindUrl } from '../../platforms/cloudtentacles/virtual-number-service.js'
|
||||||
import { resolveCloudtentaclesConfig } from '../../platforms/cloudtentacles/helpers.js'
|
import { resolveCloudtentaclesConfig } from '../../platforms/cloudtentacles/helpers.js'
|
||||||
import { notifyKuaishouCloudBindUrlRefreshFailed } from '../../notification/domain-notifications.js'
|
|
||||||
import { createHttpError } from '../../../utils/http.js'
|
import { createHttpError } from '../../../utils/http.js'
|
||||||
import { nowIso } from '../../../utils/time.js'
|
import { nowIso } from '../../../utils/time.js'
|
||||||
import { TASK_STATUS } from '../../../domain/task-status.js'
|
|
||||||
import {
|
import {
|
||||||
isKuaishouCloudBindUrlFresh,
|
isKuaishouCloudBindUrlFresh,
|
||||||
isKuaishouCloudBindingMutationFrozen,
|
isKuaishouCloudBindingMutationFrozen,
|
||||||
@@ -14,8 +11,7 @@ import {
|
|||||||
normalizeKuaishouCloudRoleInfo,
|
normalizeKuaishouCloudRoleInfo,
|
||||||
type JsonObject,
|
type JsonObject,
|
||||||
} from './domain.js'
|
} from './domain.js'
|
||||||
import { resolvePersistedCloudtentaclesContextBySourceKeys } from './cloudtentacles-context.js'
|
import { parseTaskContext } from './task-context.js'
|
||||||
import { normalizeActor, parseTaskContext } from './task-context.js'
|
|
||||||
import { buildRoleStateFromCurrentInfo } from './role-state.js'
|
import { buildRoleStateFromCurrentInfo } from './role-state.js'
|
||||||
import { refreshKuaishouCloudTaskBindUrl } from './prepare-fulfillment.js'
|
import { refreshKuaishouCloudTaskBindUrl } from './prepare-fulfillment.js'
|
||||||
import type { TaskRow } from '../../../types/repository/rows.js'
|
import type { TaskRow } from '../../../types/repository/rows.js'
|
||||||
@@ -118,70 +114,3 @@ export async function probeKuaishouCloudTaskBindUrl(task: TaskRow, options: Json
|
|||||||
probe,
|
probe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {any} task
|
|
||||||
* @param {{ taskContext?: any, flow?: any, now?: string, actor?: any, error?: unknown }} [input]
|
|
||||||
*/
|
|
||||||
async function markKuaishouCloudBindUrlRefreshFailed(
|
|
||||||
task: TaskRow,
|
|
||||||
{ taskContext, flow, now, actor, error }: JsonObject = {},
|
|
||||||
) {
|
|
||||||
const errorMessage =
|
|
||||||
error instanceof Error ? error.message : String(error || '新绑定链接准备失败')
|
|
||||||
const nextContext = {
|
|
||||||
...taskContext,
|
|
||||||
kuaishouCloudFulfillment: {
|
|
||||||
...flow,
|
|
||||||
binding: {
|
|
||||||
...flow.binding,
|
|
||||||
prepareStatus: 'pending',
|
|
||||||
vnId: 0,
|
|
||||||
vnPhone: '',
|
|
||||||
bindUrl: '',
|
|
||||||
bindPreparedAt: null,
|
|
||||||
bindExpiresAt: null,
|
|
||||||
bindProbeAt: now,
|
|
||||||
bindProbeStatus: 'refresh_failed',
|
|
||||||
bindProbeMessage: errorMessage,
|
|
||||||
roleName: '',
|
|
||||||
roleId: '',
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
status: 'pending',
|
|
||||||
name: '',
|
|
||||||
rid: '',
|
|
||||||
refreshedAt: now,
|
|
||||||
errorMessage: '绑定链接已过期,旧号码已退还,新链接准备失败,请稍后刷新或联系客服处理',
|
|
||||||
rawInfo: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedTask = await updateTask(task.id, {
|
|
||||||
task_status: TASK_STATUS.PENDING_BINDING_PREPARE,
|
|
||||||
role_id: '',
|
|
||||||
role_name: '',
|
|
||||||
last_error: `绑定链接过期,旧号码已退还,新链接准备失败:${errorMessage}`,
|
|
||||||
context_json: JSON.stringify(nextContext),
|
|
||||||
updated_at: now,
|
|
||||||
})
|
|
||||||
|
|
||||||
await createTaskEvent(
|
|
||||||
task.id,
|
|
||||||
'kuaishou_cloud_bind_url_refresh_failed',
|
|
||||||
{
|
|
||||||
source: 'system_refresh_expired_bind_url',
|
|
||||||
errorMessage,
|
|
||||||
actor,
|
|
||||||
},
|
|
||||||
now,
|
|
||||||
)
|
|
||||||
|
|
||||||
await notifyKuaishouCloudBindUrlRefreshFailed({
|
|
||||||
task: updatedTask,
|
|
||||||
errorMessage,
|
|
||||||
})
|
|
||||||
|
|
||||||
return updatedTask
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ export async function rebindKuaishouCloudTaskRole(task: TaskRow, options: JsonOb
|
|||||||
now,
|
now,
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
oldNumberBackStatus = 'failed'
|
|
||||||
oldNumberBackError = error instanceof Error ? error.message : String(error || '退号失败')
|
oldNumberBackError = error instanceof Error ? error.message : String(error || '退号失败')
|
||||||
const wrapped = wrapCloudtentaclesOperationError(error, {
|
const wrapped = wrapCloudtentaclesOperationError(error, {
|
||||||
action: 'vn_back',
|
action: 'vn_back',
|
||||||
@@ -451,7 +450,7 @@ async function rebindByRefreshingExistingVnBindUrl(input: {
|
|||||||
now,
|
now,
|
||||||
} = input
|
} = input
|
||||||
|
|
||||||
let bindUrl = ''
|
let bindUrl
|
||||||
try {
|
try {
|
||||||
const bindUrlResult = await getCloudtentaclesBindUrl({
|
const bindUrlResult = await getCloudtentaclesBindUrl({
|
||||||
...cloudContext,
|
...cloudContext,
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export async function returnKuaishouCloudFulfillmentTask(task: TaskRow, options:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ticketCode = String(flow.ticket.code || '').trim()
|
const ticketCode = String(flow.ticket.code || '').trim()
|
||||||
let consumeStatus = 'pending'
|
let consumeStatus
|
||||||
let consumeErrorMessage = ''
|
let consumeErrorMessage = ''
|
||||||
let consumedAt: string | null = null
|
let consumedAt: string | null = null
|
||||||
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED
|
let nextTaskStatus: TaskStatus = TASK_STATUS.COMPLETED
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export function normalizeCloudtentaclesMatchName(value: unknown) {
|
export function normalizeCloudtentaclesMatchName(value: unknown) {
|
||||||
return String(value || '')
|
return String(value || '')
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/[【】\[\]()()]/g, ' ')
|
.replace(/[【】[\]()()]/g, ' ')
|
||||||
.replace(/(自动发货|秒发|极速发货|官方直充|官方充值)/gi, ' ')
|
.replace(/(自动发货|秒发|极速发货|官方直充|官方充值)/gi, ' ')
|
||||||
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
||||||
.replace(/\s+/g, ' ')
|
.replace(/\s+/g, ' ')
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function encryptCloudtentaclesPayload(payload: JsonObject = {}, options:
|
|||||||
r: randomValue,
|
r: randomValue,
|
||||||
plaintext,
|
plaintext,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch {
|
||||||
throw createHttpError('cloudtentacles 加密失败', {
|
throw createHttpError('cloudtentacles 加密失败', {
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
errorCode: 'cloudtentacles_encrypt_failed',
|
errorCode: 'cloudtentacles_encrypt_failed',
|
||||||
|
|||||||
@@ -220,11 +220,6 @@ function normalizePositiveInteger(value: unknown, fallback: number) {
|
|||||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeInteger(value: unknown, fallback: number) {
|
|
||||||
const parsed = Number(value)
|
|
||||||
return Number.isInteger(parsed) ? parsed : fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeHeaderMap(extra: unknown) {
|
function normalizeHeaderMap(extra: unknown) {
|
||||||
if (!extra || typeof extra !== 'object') {
|
if (!extra || typeof extra !== 'object') {
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ async function waitForCloudtentaclesSlot(bucketKey: string, intervalMs: number)
|
|||||||
|
|
||||||
await previousQueue
|
await previousQueue
|
||||||
|
|
||||||
let waitMs = 0
|
let waitMs
|
||||||
try {
|
try {
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const nextAvailableAt = bucketNextAvailableAt.get(bucketKey) || 0
|
const nextAvailableAt = bucketNextAvailableAt.get(bucketKey) || 0
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ function assertCommonPayload(
|
|||||||
accessToken: string
|
accessToken: string
|
||||||
paramRaw: string
|
paramRaw: string
|
||||||
},
|
},
|
||||||
config = assertKuaishouIndustryConfig(),
|
_config = assertKuaishouIndustryConfig(),
|
||||||
) {
|
) {
|
||||||
if (!payload.signMethod) {
|
if (!payload.signMethod) {
|
||||||
throw createHttpError('缺少 signMethod', {
|
throw createHttpError('缺少 signMethod', {
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ async function saveTokenPayload(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeTokenResponse(json: JsonObject, currentConfig: KuaishouIndustrySourceConfig) {
|
function normalizeTokenResponse(json: JsonObject, _currentConfig: KuaishouIndustrySourceConfig) {
|
||||||
const payload = isPlainObject(json.data) ? json.data : json
|
const payload = isPlainObject(json.data) ? json.data : json
|
||||||
const accessToken = pickFirstString(payload, ['access_token', 'accessToken', 'accessTokenValue'])
|
const accessToken = pickFirstString(payload, ['access_token', 'accessToken', 'accessTokenValue'])
|
||||||
const refreshToken = pickFirstString(payload, [
|
const refreshToken = pickFirstString(payload, [
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import crypto from 'node:crypto'
|
|
||||||
|
|
||||||
import { runtimeConfig } from '../../config/runtime.js'
|
|
||||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||||
import {
|
import {
|
||||||
acceptWorkOrderAndSettle,
|
acceptWorkOrderAndSettle,
|
||||||
@@ -9,45 +6,27 @@ import {
|
|||||||
cancelAssignedWorkOrder,
|
cancelAssignedWorkOrder,
|
||||||
returnAssignedWorkOrderToHall,
|
returnAssignedWorkOrderToHall,
|
||||||
unassignWorkOrder,
|
unassignWorkOrder,
|
||||||
countWorkerAcceptedOrders,
|
|
||||||
countWorkerActiveOrders,
|
countWorkerActiveOrders,
|
||||||
countWorkCategoryUsages,
|
countWorkCategoryUsages,
|
||||||
countWorkerLevelUsages,
|
countWorkerLevelUsages,
|
||||||
countWorkOrderPendingSharingSubmissions,
|
countWorkOrderPendingSharingSubmissions,
|
||||||
countTimeoutEventsByWorkerIds,
|
countTimeoutEventsByWorkerIds,
|
||||||
cancelWorkerWorkOrder,
|
|
||||||
countWorkerCancellationsSince,
|
|
||||||
createWorkOrder,
|
createWorkOrder,
|
||||||
createWorkOrderEvent,
|
createWorkOrderEvent,
|
||||||
createWorkerFinanceRequest,
|
|
||||||
createWorkerUser,
|
|
||||||
deductPendingDepositUnfreeze,
|
deductPendingDepositUnfreeze,
|
||||||
deleteWorkCategory,
|
deleteWorkCategory,
|
||||||
deleteWorkProductRule,
|
deleteWorkProductRule,
|
||||||
deleteWorkOrder,
|
deleteWorkOrder,
|
||||||
deleteWorkerLevel,
|
deleteWorkerLevel,
|
||||||
getWorkerFinanceRequestById,
|
getWorkerFinanceRequestById,
|
||||||
getWorkerFinanceRequestSummary,
|
|
||||||
getWorkCategoryById,
|
getWorkCategoryById,
|
||||||
getWorkCategoryByKey,
|
|
||||||
getWorkerLevelById,
|
getWorkerLevelById,
|
||||||
getWorkerLevelByKey,
|
getWorkerLevelByKey,
|
||||||
getWorkerUserByInviteCode,
|
|
||||||
getWorkerUserById,
|
getWorkerUserById,
|
||||||
getWorkerUserByUsername,
|
|
||||||
getWorkOrderById,
|
|
||||||
getWorkOrderByOrderItemId,
|
getWorkOrderByOrderItemId,
|
||||||
getWorkOrderShare,
|
|
||||||
getWorkProductRuleByKey,
|
getWorkProductRuleByKey,
|
||||||
grabWorkOrder,
|
|
||||||
incrementWorkerSessionVersion,
|
|
||||||
joinWorkOrderShare,
|
|
||||||
listAllWorkCategories,
|
listAllWorkCategories,
|
||||||
listPendingMaterialWorkOrdersByPlatformOrderId,
|
|
||||||
listWorkerFinanceRequests,
|
listWorkerFinanceRequests,
|
||||||
listWorkerSharesByWorker,
|
|
||||||
listWorkerWalletLedgers,
|
|
||||||
listWorkCategories,
|
|
||||||
listWorkOrders,
|
listWorkOrders,
|
||||||
listWorkProductRules,
|
listWorkProductRules,
|
||||||
listWorkerLevels,
|
listWorkerLevels,
|
||||||
@@ -57,36 +36,21 @@ import {
|
|||||||
sumPendingUnfreezeByOrderIds,
|
sumPendingUnfreezeByOrderIds,
|
||||||
resolveProblemWorkOrder,
|
resolveProblemWorkOrder,
|
||||||
reviewWorkerFinanceRequest,
|
reviewWorkerFinanceRequest,
|
||||||
submitWorkOrderShareAcceptance,
|
|
||||||
updateWorkOrder,
|
updateWorkOrder,
|
||||||
updateWorkOrderBasic,
|
updateWorkOrderBasic,
|
||||||
updateWorkerPassword,
|
|
||||||
updateWorkerUser,
|
updateWorkerUser,
|
||||||
upsertWorkCategory,
|
upsertWorkCategory,
|
||||||
upsertWorkProductRule,
|
upsertWorkProductRule,
|
||||||
upsertWorkerLevel,
|
upsertWorkerLevel,
|
||||||
type WorkCategoryRow,
|
|
||||||
type WorkerFinanceRequestRow,
|
|
||||||
type WorkOrderRow,
|
type WorkOrderRow,
|
||||||
type WorkProductRuleRow,
|
|
||||||
type WorkerLevelRow,
|
|
||||||
type WorkOrderShareRow,
|
type WorkOrderShareRow,
|
||||||
type WorkerWalletLedgerRow,
|
|
||||||
type WorkerUserRow,
|
|
||||||
type GrabWorkOrderFailureReason,
|
|
||||||
type ProblemWorkOrderResolutionAction,
|
|
||||||
} from '../../repositories/worker-platform/index.js'
|
} from '../../repositories/worker-platform/index.js'
|
||||||
import type { JsonObject } from '../../types/json.js'
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { randomId } from '../../utils/random.js'
|
import { randomId } from '../../utils/random.js'
|
||||||
import { nowIso, addHours } from '../../utils/time.js'
|
import { nowIso } from '../../utils/time.js'
|
||||||
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
|
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
|
||||||
import {
|
|
||||||
normalizeStoredFileUrl,
|
|
||||||
refreshStoredFileUrl,
|
|
||||||
refreshUploadedFileUrls,
|
|
||||||
} from '../file-storage/file-storage-service.js'
|
|
||||||
import { getWorkerFinanceConfig, saveWorkerFinanceConfig } from './worker-finance-config-service.js'
|
import { getWorkerFinanceConfig, saveWorkerFinanceConfig } from './worker-finance-config-service.js'
|
||||||
import {
|
import {
|
||||||
consumeIndustryVouchersBeforeWorkOrderAssign,
|
consumeIndustryVouchersBeforeWorkOrderAssign,
|
||||||
|
|||||||
@@ -1,61 +1,8 @@
|
|||||||
import crypto from 'node:crypto'
|
import crypto from 'node:crypto'
|
||||||
|
|
||||||
import { runtimeConfig } from '../../config/runtime.js'
|
import { runtimeConfig } from '../../config/runtime.js'
|
||||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
|
||||||
import { listOrderItemsByOrderId } from '../../repositories/order-item-repo.js'
|
|
||||||
import { findLatestOrderByAnyPlatformOrderId, getOrderById } from '../../repositories/order-repo.js'
|
|
||||||
import {
|
import {
|
||||||
acceptWorkOrderAndSettle,
|
|
||||||
addWorkerWalletCredit,
|
addWorkerWalletCredit,
|
||||||
countWorkerAcceptedOrders,
|
|
||||||
countWorkerActiveOrders,
|
|
||||||
countWorkCategoryUsages,
|
|
||||||
countWorkerLevelUsages,
|
|
||||||
countWorkOrderPendingSharingSubmissions,
|
|
||||||
cancelWorkerWorkOrder,
|
|
||||||
countWorkerCancellationsSince,
|
|
||||||
createWorkOrder,
|
|
||||||
createWorkOrderEvent,
|
|
||||||
createWorkerFinanceRequest,
|
|
||||||
createWorkerUser,
|
|
||||||
deleteWorkCategory,
|
|
||||||
deleteWorkerLevel,
|
|
||||||
getWorkerFinanceRequestById,
|
|
||||||
getWorkerFinanceRequestSummary,
|
|
||||||
getWorkCategoryById,
|
|
||||||
getWorkCategoryByKey,
|
|
||||||
getWorkerLevelById,
|
|
||||||
getWorkerLevelByKey,
|
|
||||||
getWorkerUserByInviteCode,
|
|
||||||
getWorkerUserById,
|
|
||||||
getWorkerUserByUsername,
|
|
||||||
getWorkOrderById,
|
|
||||||
getWorkOrderByOrderItemId,
|
|
||||||
getWorkOrderShare,
|
|
||||||
grabWorkOrder,
|
|
||||||
incrementWorkerSessionVersion,
|
|
||||||
joinWorkOrderShare,
|
|
||||||
listAllWorkCategories,
|
|
||||||
listPendingMaterialWorkOrdersByPlatformOrderId,
|
|
||||||
listWorkerFinanceRequests,
|
|
||||||
listWorkerSharesByWorker,
|
|
||||||
listWorkerWalletLedgers,
|
|
||||||
listWorkCategories,
|
|
||||||
listWorkOrders,
|
|
||||||
listWorkProductRules,
|
|
||||||
listWorkerLevels,
|
|
||||||
listWorkerUsers,
|
|
||||||
listWorkOrderShares,
|
|
||||||
listWorkOrderSharesByOrderIds,
|
|
||||||
resolveProblemWorkOrder,
|
|
||||||
reviewWorkerFinanceRequest,
|
|
||||||
submitWorkOrderShareAcceptance,
|
|
||||||
updateWorkOrder,
|
|
||||||
updateWorkerPassword,
|
|
||||||
updateWorkerUser,
|
|
||||||
upsertWorkCategory,
|
|
||||||
upsertWorkProductRule,
|
|
||||||
upsertWorkerLevel,
|
|
||||||
type WorkCategoryRow,
|
type WorkCategoryRow,
|
||||||
type WorkerFinanceRequestRow,
|
type WorkerFinanceRequestRow,
|
||||||
type WorkOrderRow,
|
type WorkOrderRow,
|
||||||
@@ -70,15 +17,13 @@ import {
|
|||||||
import type { JsonObject } from '../../types/json.js'
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { randomId } from '../../utils/random.js'
|
|
||||||
import { nowIso, addHours } from '../../utils/time.js'
|
import { nowIso, addHours } from '../../utils/time.js'
|
||||||
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
|
import { safeParseJson } from '../admin/admin-query-utils.js'
|
||||||
import {
|
import {
|
||||||
normalizeStoredFileUrl,
|
normalizeStoredFileUrl,
|
||||||
refreshStoredFileUrl,
|
refreshStoredFileUrl,
|
||||||
refreshUploadedFileUrls,
|
refreshUploadedFileUrls,
|
||||||
} from '../file-storage/file-storage-service.js'
|
} from '../file-storage/file-storage-service.js'
|
||||||
import { getWorkerFinanceConfig, saveWorkerFinanceConfig } from './worker-finance-config-service.js'
|
|
||||||
|
|
||||||
export const DEFAULT_LEVEL_KEY = 'vip1'
|
export const DEFAULT_LEVEL_KEY = 'vip1'
|
||||||
export const DEFAULT_LEVEL_NAME = 'VIP1'
|
export const DEFAULT_LEVEL_NAME = 'VIP1'
|
||||||
@@ -414,8 +359,8 @@ export function mapWorkOrderForWorker(
|
|||||||
) {
|
) {
|
||||||
const mapped = mapWorkOrderAdmin(workOrder)
|
const mapped = mapWorkOrderAdmin(workOrder)
|
||||||
const {
|
const {
|
||||||
requiredDepositAmount,
|
requiredDepositAmount: _requiredDepositAmount,
|
||||||
depositThresholdAmount,
|
depositThresholdAmount: _depositThresholdAmount,
|
||||||
worker: _worker,
|
worker: _worker,
|
||||||
orderId: _orderId,
|
orderId: _orderId,
|
||||||
orderItemId: _orderItemId,
|
orderItemId: _orderItemId,
|
||||||
|
|||||||
@@ -2,32 +2,21 @@ import crypto from 'node:crypto'
|
|||||||
|
|
||||||
import { runtimeConfig } from '../../config/runtime.js'
|
import { runtimeConfig } from '../../config/runtime.js'
|
||||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||||
import { listOrderItemsByOrderId } from '../../repositories/order-item-repo.js'
|
|
||||||
import { findLatestOrderByAnyPlatformOrderId, getOrderById } from '../../repositories/order-repo.js'
|
|
||||||
import {
|
import {
|
||||||
acceptWorkOrderAndSettle,
|
acceptWorkOrderAndSettle,
|
||||||
addWorkerWalletCredit,
|
|
||||||
countWorkerAcceptedOrders,
|
countWorkerAcceptedOrders,
|
||||||
countWorkerActiveOrders,
|
countWorkerActiveOrders,
|
||||||
countWorkerTimeoutEvents,
|
countWorkerTimeoutEvents,
|
||||||
countWorkerWithdrawRequestsOnDay,
|
countWorkerWithdrawRequestsOnDay,
|
||||||
countWorkCategoryUsages,
|
|
||||||
countWorkerLevelUsages,
|
|
||||||
countWorkOrderPendingSharingSubmissions,
|
countWorkOrderPendingSharingSubmissions,
|
||||||
countWorkerSmsCodesOnDay,
|
countWorkerSmsCodesOnDay,
|
||||||
consumeWorkerSmsCode,
|
consumeWorkerSmsCode,
|
||||||
createWorkerSmsCode,
|
createWorkerSmsCode,
|
||||||
createWorkOrder,
|
|
||||||
createWorkOrderEvent,
|
createWorkOrderEvent,
|
||||||
createWorkerFinanceRequest,
|
createWorkerFinanceRequest,
|
||||||
createWorkerUser,
|
createWorkerUser,
|
||||||
deleteWorkCategory,
|
|
||||||
deleteWorkerLevel,
|
|
||||||
getWorkerFinanceRequestById,
|
|
||||||
getWorkerFinanceRequestSummary,
|
getWorkerFinanceRequestSummary,
|
||||||
getWorkCategoryById,
|
|
||||||
getWorkCategoryByKey,
|
getWorkCategoryByKey,
|
||||||
getWorkerLevelById,
|
|
||||||
getWorkerLevelByKey,
|
getWorkerLevelByKey,
|
||||||
getLatestWorkerSmsCode,
|
getLatestWorkerSmsCode,
|
||||||
getWorkerUserByInviteCode,
|
getWorkerUserByInviteCode,
|
||||||
@@ -36,12 +25,10 @@ import {
|
|||||||
getWorkerUserByUsername,
|
getWorkerUserByUsername,
|
||||||
getWorkerUserByDisplayName,
|
getWorkerUserByDisplayName,
|
||||||
getWorkOrderById,
|
getWorkOrderById,
|
||||||
getWorkOrderByOrderItemId,
|
|
||||||
getWorkOrderShare,
|
getWorkOrderShare,
|
||||||
grabWorkOrder,
|
grabWorkOrder,
|
||||||
incrementWorkerSessionVersion,
|
incrementWorkerSessionVersion,
|
||||||
joinWorkOrderShare,
|
joinWorkOrderShare,
|
||||||
listAllWorkCategories,
|
|
||||||
listPendingMaterialWorkOrdersByPlatformOrderId,
|
listPendingMaterialWorkOrdersByPlatformOrderId,
|
||||||
listWorkerFinanceRequests,
|
listWorkerFinanceRequests,
|
||||||
listWorkerCompletionLeaderboard,
|
listWorkerCompletionLeaderboard,
|
||||||
@@ -50,16 +37,10 @@ import {
|
|||||||
listWorkerWorkOrderNotes,
|
listWorkerWorkOrderNotes,
|
||||||
listWorkCategories,
|
listWorkCategories,
|
||||||
listWorkOrders,
|
listWorkOrders,
|
||||||
listWorkProductRules,
|
|
||||||
listWorkerLevels,
|
listWorkerLevels,
|
||||||
listWorkerUsers,
|
|
||||||
listWorkOrderShares,
|
|
||||||
listWorkOrderSharesByOrderIds,
|
|
||||||
listDueDepositUnfreezes,
|
listDueDepositUnfreezes,
|
||||||
listOverdueWorkOrders,
|
listOverdueWorkOrders,
|
||||||
releaseDepositUnfreeze,
|
releaseDepositUnfreeze,
|
||||||
resolveProblemWorkOrder,
|
|
||||||
reviewWorkerFinanceRequest,
|
|
||||||
settleOverdueWorkOrder,
|
settleOverdueWorkOrder,
|
||||||
submitWorkOrderShareAcceptance,
|
submitWorkOrderShareAcceptance,
|
||||||
updateWorkOrder,
|
updateWorkOrder,
|
||||||
@@ -69,34 +50,18 @@ import {
|
|||||||
updateWorkOrderShareDraftAcceptance,
|
updateWorkOrderShareDraftAcceptance,
|
||||||
upsertWorkerWorkOrderNote,
|
upsertWorkerWorkOrderNote,
|
||||||
updateWorkerPassword,
|
updateWorkerPassword,
|
||||||
updateWorkerUser,
|
|
||||||
upsertWorkCategory,
|
upsertWorkCategory,
|
||||||
upsertWorkProductRule,
|
|
||||||
upsertWorkerLevel,
|
upsertWorkerLevel,
|
||||||
type WorkCategoryRow,
|
|
||||||
type WorkerFinanceRequestRow,
|
|
||||||
type WorkOrderRow,
|
type WorkOrderRow,
|
||||||
type WorkProductRuleRow,
|
|
||||||
type WorkerLevelRow,
|
|
||||||
type WorkOrderShareRow,
|
type WorkOrderShareRow,
|
||||||
type WorkerWalletLedgerRow,
|
|
||||||
type WorkerUserRow,
|
type WorkerUserRow,
|
||||||
type GrabWorkOrderFailureReason,
|
|
||||||
type ProblemWorkOrderResolutionAction,
|
|
||||||
} from '../../repositories/worker-platform/index.js'
|
} from '../../repositories/worker-platform/index.js'
|
||||||
import type { JsonObject } from '../../types/json.js'
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { randomId } from '../../utils/random.js'
|
import { nowIso } from '../../utils/time.js'
|
||||||
import { nowIso, addHours } from '../../utils/time.js'
|
|
||||||
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
|
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
|
||||||
import { getSmsProvider } from '../sms/index.js'
|
import { getSmsProvider } from '../sms/index.js'
|
||||||
import {
|
import { getWorkerFinanceConfig } from './worker-finance-config-service.js'
|
||||||
normalizeStoredFileUrl,
|
|
||||||
refreshStoredFileUrl,
|
|
||||||
refreshUploadedFileUrls,
|
|
||||||
} from '../file-storage/file-storage-service.js'
|
|
||||||
import { getWorkerFinanceConfig, saveWorkerFinanceConfig } from './worker-finance-config-service.js'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DEFAULT_CATEGORY_KEY,
|
DEFAULT_CATEGORY_KEY,
|
||||||
@@ -139,7 +104,6 @@ import {
|
|||||||
signWorkerPayload,
|
signWorkerPayload,
|
||||||
throwGrabWorkOrderFailure,
|
throwGrabWorkOrderFailure,
|
||||||
validateWorkerPassword,
|
validateWorkerPassword,
|
||||||
validateWorkerUsername,
|
|
||||||
verifyWorkerPassword,
|
verifyWorkerPassword,
|
||||||
} from './mappers.js'
|
} from './mappers.js'
|
||||||
|
|
||||||
@@ -355,7 +319,7 @@ function hashSmsCode(code: string): string {
|
|||||||
.digest('hex')
|
.digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateInviteCode(now: string): Promise<string> {
|
async function generateInviteCode(_now: string): Promise<string> {
|
||||||
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
|
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
|
||||||
for (let attempt = 0; attempt < INVITE_CODE_RETRY_LIMIT; attempt++) {
|
for (let attempt = 0; attempt < INVITE_CODE_RETRY_LIMIT; attempt++) {
|
||||||
const candidate = Array.from(
|
const candidate = Array.from(
|
||||||
@@ -464,7 +428,7 @@ export async function verifyWorkerSessionToken(token: unknown): Promise<WorkerSe
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload: JsonObject = {}
|
let payload: JsonObject
|
||||||
try {
|
try {
|
||||||
payload = JSON.parse(Buffer.from(encodedPayload, 'base64url').toString('utf8'))
|
payload = JSON.parse(Buffer.from(encodedPayload, 'base64url').toString('utf8'))
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export type StrictJsonObject = { [key: string]: StrictJson }
|
|||||||
* 宽松 JSON 对象袋(兼容既有履约 context / 平台响应)。
|
* 宽松 JSON 对象袋(兼容既有履约 context / 平台响应)。
|
||||||
* 值使用 any 仅为兼容深层属性链;新增代码优先 TaskContext 或 StrictJsonObject。
|
* 值使用 any 仅为兼容深层属性链;新增代码优先 TaskContext 或 StrictJsonObject。
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export type JsonObject = Record<string, any>
|
export type JsonObject = Record<string, any>
|
||||||
|
|
||||||
/** @deprecated 使用 JsonObject */
|
/** @deprecated 使用 JsonObject */
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "scripts/**/*.ts"],
|
||||||
|
"exclude": ["node_modules", "dist", "data"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import eslint from '@eslint/js'
|
||||||
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import globals from 'globals'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{
|
||||||
|
ignores: ['dist/**', 'node_modules/**'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['src/**/*.{ts,tsx}', 'tests/**/*.{ts,tsx}', 'vite.config.ts'],
|
||||||
|
extends: [
|
||||||
|
eslint.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
reactHooks.configs.flat.recommended,
|
||||||
|
reactRefresh.configs.vite,
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
project: './tsconfig.eslint.json',
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-floating-promises': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
ignoreIIFE: true,
|
||||||
|
ignoreVoid: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-misused-promises': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
checksVoidReturn: {
|
||||||
|
attributes: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
caughtErrorsIgnorePattern: '^_',
|
||||||
|
destructuredArrayIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'react-hooks/refs': 'warn',
|
||||||
|
'react-hooks/set-state-in-effect': 'warn',
|
||||||
|
'react-refresh/only-export-components': 'warn',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['src/**/*.test.{ts,tsx}', 'tests/**/*.{ts,tsx}'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-floating-promises': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
Generated
+1714
File diff suppressed because it is too large
Load Diff
@@ -6,11 +6,14 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
"format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write \"src/**/*.{ts,tsx,js,jsx,json,css}\" \"tests/**/*.{ts,tsx,js,jsx}\" package.json tsconfig.json vite.config.ts index.html",
|
"format": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write \"src/**/*.{ts,tsx,js,jsx,json,css}\" \"tests/**/*.{ts,tsx,js,jsx}\" eslint.config.js package.json tsconfig.json tsconfig.eslint.json vite.config.ts index.html",
|
||||||
"format:check": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check \"src/**/*.{ts,tsx,js,jsx,json,css}\" \"tests/**/*.{ts,tsx,js,jsx}\" package.json tsconfig.json vite.config.ts index.html",
|
"format:check": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check \"src/**/*.{ts,tsx,js,jsx,json,css}\" \"tests/**/*.{ts,tsx,js,jsx}\" eslint.config.js package.json tsconfig.json tsconfig.eslint.json vite.config.ts index.html",
|
||||||
|
"lint": "eslint \"src/**/*.{ts,tsx}\" \"tests/**/*.{ts,tsx}\" vite.config.ts",
|
||||||
|
"lint:check": "npm run lint -- --quiet",
|
||||||
|
"lint:fix": "npm run lint -- --fix",
|
||||||
"test": "node --experimental-strip-types --test tests/*.test.ts",
|
"test": "node --experimental-strip-types --test tests/*.test.ts",
|
||||||
"typecheck": "tsc -b --noEmit",
|
"typecheck": "tsc -b --noEmit",
|
||||||
"check": "npm run format:check && npm run typecheck && npm test && npm run build",
|
"check": "npm run format:check && npm run lint:check && npm run typecheck && npm test && npm run build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -25,13 +28,19 @@
|
|||||||
"react-router": "^7.10.1"
|
"react-router": "^7.10.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "10.0.1",
|
||||||
"@types/node": "^25.6.0",
|
"@types/node": "^25.6.0",
|
||||||
"@types/qrcode": "^1.5.6",
|
"@types/qrcode": "^1.5.6",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react": "^19.2.7",
|
||||||
"@types/react-dom": "^19.2.3",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@vitejs/plugin-react": "^6.0.1",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
|
"eslint": "10.8.1",
|
||||||
|
"eslint-plugin-react-hooks": "7.1.1",
|
||||||
|
"eslint-plugin-react-refresh": "0.5.4",
|
||||||
|
"globals": "17.11.0",
|
||||||
"prettier": "3.8.3",
|
"prettier": "3.8.3",
|
||||||
"typescript": "~6.0.2",
|
"typescript": "~6.0.2",
|
||||||
|
"typescript-eslint": "8.67.0",
|
||||||
"vite": "^8.0.7"
|
"vite": "^8.0.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'
|
|||||||
|
|
||||||
export function DeadlineCountdown({
|
export function DeadlineCountdown({
|
||||||
deadlineAt,
|
deadlineAt,
|
||||||
showExpired = false,
|
showExpired: _showExpired = false,
|
||||||
}: {
|
}: {
|
||||||
deadlineAt: string
|
deadlineAt: string
|
||||||
showExpired?: boolean
|
showExpired?: boolean
|
||||||
|
|||||||
@@ -169,15 +169,17 @@ export default function ImageUpload({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [captureGlobalPaste])
|
}, [captureGlobalPaste])
|
||||||
|
|
||||||
function handleWrapperFocus(event: FocusEvent<HTMLDivElement>) {
|
function handleWrapperFocus(_event: FocusEvent<HTMLDivElement>) {
|
||||||
if (captureGlobalPaste) activateGlobalPasteTarget()
|
if (captureGlobalPaste) activateGlobalPasteTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleWrapperClick(event: MouseEvent<HTMLDivElement>) {
|
function handleWrapperClick(_event: MouseEvent<HTMLDivElement>) {
|
||||||
if (captureGlobalPaste) activateGlobalPasteTarget()
|
if (captureGlobalPaste) activateGlobalPasteTarget()
|
||||||
}
|
}
|
||||||
|
|
||||||
const customRequest: UploadProps['customRequest'] = async (options) => {
|
async function uploadFromRequest(
|
||||||
|
options: Parameters<NonNullable<UploadProps['customRequest']>>[0],
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const uploaded = await uploadFile(options.file as File, scene, scope)
|
const uploaded = await uploadFile(options.file as File, scene, scope)
|
||||||
// 多文件选择会并发执行 customRequest,必须以 ref 中的最新列表累加,避免后完成的上传覆盖前面的图片。
|
// 多文件选择会并发执行 customRequest,必须以 ref 中的最新列表累加,避免后完成的上传覆盖前面的图片。
|
||||||
@@ -191,6 +193,10 @@ export default function ImageUpload({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customRequest: UploadProps['customRequest'] = (options) => {
|
||||||
|
void uploadFromRequest(options)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`image-upload-droppable ${isDragging ? 'is-dragging' : ''}`}
|
className={`image-upload-droppable ${isDragging ? 'is-dragging' : ''}`}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export default function AdminLayout() {
|
|||||||
} finally {
|
} finally {
|
||||||
clearAdminSession()
|
clearAdminSession()
|
||||||
message.success('已退出后台')
|
message.success('已退出后台')
|
||||||
navigate('/admin/login', { replace: true })
|
void navigate('/admin/login', { replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +185,9 @@ export default function AdminLayout() {
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
menu={{
|
menu={{
|
||||||
items: [{ key: 'logout', label: '退出登录' }],
|
items: [{ key: 'logout', label: '退出登录' }],
|
||||||
onClick: submitLogout,
|
onClick: () => {
|
||||||
|
void submitLogout()
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default function WorkerLayout() {
|
|||||||
} finally {
|
} finally {
|
||||||
clearWorkerSession()
|
clearWorkerSession()
|
||||||
message.success('已退出登录')
|
message.success('已退出登录')
|
||||||
navigate('/', { replace: true })
|
void navigate('/', { replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -918,7 +918,9 @@ export default function AdminKuaishouIndustryPage() {
|
|||||||
current: voucherFilters.page,
|
current: voucherFilters.page,
|
||||||
pageSize: voucherFilters.pageSize,
|
pageSize: voucherFilters.pageSize,
|
||||||
total: voucherTotal,
|
total: voucherTotal,
|
||||||
onChange: (page, pageSize) => loadVouchers({ page, pageSize }),
|
onChange: (page, pageSize) => {
|
||||||
|
void loadVouchers({ page, pageSize })
|
||||||
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function AdminLoginPage() {
|
|||||||
})
|
})
|
||||||
setAdminSession(response.data.token, response.data.expiresAt, response.data.user)
|
setAdminSession(response.data.token, response.data.expiresAt, response.data.user)
|
||||||
message.success('登录成功')
|
message.success('登录成功')
|
||||||
navigate('/admin/dashboard', { replace: true })
|
void navigate('/admin/dashboard', { replace: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error(error instanceof Error ? error.message : '后台登录失败')
|
message.error(error instanceof Error ? error.message : '后台登录失败')
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ type ManualDispatchForm = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AdminTaskDetailPage() {
|
export default function AdminTaskDetailPage() {
|
||||||
const navigate = useNavigate()
|
|
||||||
const { taskId = '' } = useParams()
|
const { taskId = '' } = useParams()
|
||||||
const { message, modal } = App.useApp()
|
const { message, modal } = App.useApp()
|
||||||
const [actionLoadingKey, setActionLoadingKey] = useState('')
|
const [actionLoadingKey, setActionLoadingKey] = useState('')
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
Empty,
|
Empty,
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
Modal,
|
|
||||||
Result,
|
Result,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
|
|||||||
@@ -1,82 +1,9 @@
|
|||||||
import {
|
import { useQuery } from '@tanstack/react-query'
|
||||||
CheckOutlined,
|
import { Card, Space, Tabs } from 'antd'
|
||||||
FormOutlined,
|
import { useState } from 'react'
|
||||||
PlusOutlined,
|
|
||||||
ReloadOutlined,
|
|
||||||
SendOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
WarningOutlined,
|
|
||||||
} from '@ant-design/icons'
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import {
|
|
||||||
App,
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Descriptions,
|
|
||||||
Drawer,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
InputNumber,
|
|
||||||
Modal,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Switch,
|
|
||||||
Table,
|
|
||||||
Tabs,
|
|
||||||
Tag,
|
|
||||||
Typography,
|
|
||||||
} from 'antd'
|
|
||||||
import type { TableColumnsType } from 'antd'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
import {
|
import { fetchAdminWorkerPlatformSummary } from '@/services/admin'
|
||||||
acceptAdminWorkOrder,
|
|
||||||
createAdminMockWorkOrder,
|
|
||||||
creditAdminWorkerWallet,
|
|
||||||
deleteAdminWorkCategory,
|
|
||||||
deleteAdminWorkerLevel,
|
|
||||||
fetchAdminWorkerFinanceConfig,
|
|
||||||
fetchAdminWorkerFinanceRequests,
|
|
||||||
fetchAdminWorkCategories,
|
|
||||||
fetchAdminWorkOrderSharing,
|
|
||||||
fetchAdminWorkProductRules,
|
|
||||||
fetchAdminWorkerLevels,
|
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
|
||||||
fetchAdminWorkOrders,
|
|
||||||
markAdminWorkOrderProblem,
|
|
||||||
publishAdminWorkOrder,
|
|
||||||
reviewAdminWorkerFinanceRequest,
|
|
||||||
resolveAdminProblemWorkOrder,
|
|
||||||
reviewAdminWorkerUser,
|
|
||||||
saveAdminWorkerFinanceConfig,
|
|
||||||
saveAdminWorkCategory,
|
|
||||||
saveAdminWorkProductRule,
|
|
||||||
saveAdminWorkerLevel,
|
|
||||||
submitAdminWorkOrderMaterial,
|
|
||||||
unpublishAdminWorkOrder,
|
|
||||||
updateAdminWorkOrderSharing,
|
|
||||||
} from '@/services/admin'
|
|
||||||
import type {
|
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
|
||||||
WorkerFinanceRequest,
|
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
|
||||||
import CategoriesPanel from './panels/CategoriesPanel'
|
import CategoriesPanel from './panels/CategoriesPanel'
|
||||||
import FinancePanel from './panels/FinancePanel'
|
import FinancePanel from './panels/FinancePanel'
|
||||||
import LevelsPanel from './panels/LevelsPanel'
|
import LevelsPanel from './panels/LevelsPanel'
|
||||||
|
|||||||
@@ -1,87 +1,30 @@
|
|||||||
import {
|
import { useQuery } from '@tanstack/react-query'
|
||||||
CheckOutlined,
|
|
||||||
FormOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
ReloadOutlined,
|
|
||||||
SendOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
WarningOutlined,
|
|
||||||
} from '@ant-design/icons'
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Descriptions,
|
|
||||||
Drawer,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Switch,
|
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
|
||||||
Tag,
|
Tag,
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
|
||||||
createAdminMockWorkOrder,
|
|
||||||
creditAdminWorkerWallet,
|
|
||||||
deleteAdminWorkCategory,
|
deleteAdminWorkCategory,
|
||||||
deleteAdminWorkerLevel,
|
|
||||||
fetchAdminWorkerFinanceConfig,
|
|
||||||
fetchAdminWorkerFinanceRequests,
|
|
||||||
fetchAdminWorkCategories,
|
fetchAdminWorkCategories,
|
||||||
fetchAdminWorkOrderSharing,
|
|
||||||
fetchAdminWorkProductRules,
|
|
||||||
fetchAdminWorkerLevels,
|
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
|
||||||
fetchAdminWorkOrders,
|
|
||||||
markAdminWorkOrderProblem,
|
|
||||||
publishAdminWorkOrder,
|
|
||||||
reviewAdminWorkerFinanceRequest,
|
|
||||||
resolveAdminProblemWorkOrder,
|
|
||||||
reviewAdminWorkerUser,
|
|
||||||
saveAdminWorkerFinanceConfig,
|
|
||||||
saveAdminWorkCategory,
|
saveAdminWorkCategory,
|
||||||
saveAdminWorkProductRule,
|
|
||||||
saveAdminWorkerLevel,
|
|
||||||
submitAdminWorkOrderMaterial,
|
|
||||||
unpublishAdminWorkOrder,
|
|
||||||
updateAdminWorkOrderSharing,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type { WorkCategory } from '@/types/worker-platform'
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
|
||||||
WorkerFinanceRequest,
|
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
|
||||||
|
|
||||||
export default function CategoriesPanel() {
|
export default function CategoriesPanel() {
|
||||||
const { message } = App.useApp()
|
const { message } = App.useApp()
|
||||||
const queryClient = useQueryClient()
|
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
const [editingCategory, setEditingCategory] = useState<WorkCategory | null>(null)
|
const [editingCategory, setEditingCategory] = useState<WorkCategory | null>(null)
|
||||||
const [deletingCategory, setDeletingCategory] = useState<WorkCategory | null>(null)
|
const [deletingCategory, setDeletingCategory] = useState<WorkCategory | null>(null)
|
||||||
|
|||||||
@@ -1,89 +1,40 @@
|
|||||||
import {
|
import { ReloadOutlined } from '@ant-design/icons'
|
||||||
CheckOutlined,
|
|
||||||
FormOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
ReloadOutlined,
|
|
||||||
SendOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
WarningOutlined,
|
|
||||||
} from '@ant-design/icons'
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Descriptions,
|
Descriptions,
|
||||||
Drawer,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Switch,
|
Switch,
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
|
||||||
Tag,
|
Tag,
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
import ImageUpload from '@/components/files/ImageUpload'
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
|
||||||
createAdminMockWorkOrder,
|
|
||||||
creditAdminWorkerWallet,
|
|
||||||
deleteAdminWorkCategory,
|
|
||||||
deleteAdminWorkerLevel,
|
|
||||||
fetchAdminWorkerFinanceConfig,
|
fetchAdminWorkerFinanceConfig,
|
||||||
fetchAdminWorkerFinanceRequests,
|
fetchAdminWorkerFinanceRequests,
|
||||||
fetchAdminWorkCategories,
|
|
||||||
fetchAdminWorkOrderSharing,
|
|
||||||
fetchAdminWorkProductRules,
|
|
||||||
fetchAdminWorkerLevels,
|
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
|
||||||
fetchAdminWorkOrders,
|
|
||||||
markAdminWorkOrderProblem,
|
|
||||||
publishAdminWorkOrder,
|
|
||||||
reviewAdminWorkerFinanceRequest,
|
reviewAdminWorkerFinanceRequest,
|
||||||
resolveAdminProblemWorkOrder,
|
|
||||||
reviewAdminWorkerUser,
|
|
||||||
saveAdminWorkerFinanceConfig,
|
saveAdminWorkerFinanceConfig,
|
||||||
saveAdminWorkCategory,
|
|
||||||
saveAdminWorkProductRule,
|
|
||||||
saveAdminWorkerLevel,
|
|
||||||
submitAdminWorkOrderMaterial,
|
|
||||||
unpublishAdminWorkOrder,
|
|
||||||
updateAdminWorkOrderSharing,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type {
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
UploadedFile,
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
WorkerFinanceConfig,
|
||||||
WorkerFinanceRequest,
|
WorkerFinanceRequest,
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
} from '@/types/worker-platform'
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||||
import {
|
import { asRecord, formatMoney } from './shared'
|
||||||
asRecord,
|
|
||||||
formatMoney,
|
|
||||||
formatSharingShareStatus,
|
|
||||||
resolveSharingShareStatusColor,
|
|
||||||
} from './shared'
|
|
||||||
type FinanceConfigFormValues = {
|
type FinanceConfigFormValues = {
|
||||||
depositUnfreezeDays?: number
|
depositUnfreezeDays?: number
|
||||||
recharge?: {
|
recharge?: {
|
||||||
|
|||||||
@@ -1,83 +1,26 @@
|
|||||||
import {
|
|
||||||
CheckOutlined,
|
|
||||||
FormOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
ReloadOutlined,
|
|
||||||
SendOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
WarningOutlined,
|
|
||||||
} from '@ant-design/icons'
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Descriptions,
|
|
||||||
Drawer,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Select,
|
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Switch,
|
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
|
||||||
Tag,
|
Tag,
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
|
||||||
createAdminMockWorkOrder,
|
|
||||||
creditAdminWorkerWallet,
|
|
||||||
deleteAdminWorkCategory,
|
|
||||||
deleteAdminWorkerLevel,
|
deleteAdminWorkerLevel,
|
||||||
fetchAdminWorkerFinanceConfig,
|
|
||||||
fetchAdminWorkerFinanceRequests,
|
|
||||||
fetchAdminWorkCategories,
|
|
||||||
fetchAdminWorkOrderSharing,
|
|
||||||
fetchAdminWorkProductRules,
|
|
||||||
fetchAdminWorkerLevels,
|
fetchAdminWorkerLevels,
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
|
||||||
fetchAdminWorkOrders,
|
|
||||||
markAdminWorkOrderProblem,
|
|
||||||
publishAdminWorkOrder,
|
|
||||||
reviewAdminWorkerFinanceRequest,
|
|
||||||
resolveAdminProblemWorkOrder,
|
|
||||||
reviewAdminWorkerUser,
|
|
||||||
saveAdminWorkerFinanceConfig,
|
|
||||||
saveAdminWorkCategory,
|
|
||||||
saveAdminWorkProductRule,
|
|
||||||
saveAdminWorkerLevel,
|
saveAdminWorkerLevel,
|
||||||
submitAdminWorkOrderMaterial,
|
|
||||||
unpublishAdminWorkOrder,
|
|
||||||
updateAdminWorkOrderSharing,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type { WorkerLevel } from '@/types/worker-platform'
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
|
||||||
WorkerFinanceRequest,
|
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
|
||||||
import { formatMoney } from './shared'
|
import { formatMoney } from './shared'
|
||||||
|
|
||||||
export default function LevelsPanel() {
|
export default function LevelsPanel() {
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import {
|
|||||||
Radio,
|
Radio,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Switch,
|
Switch,
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
Tabs,
|
||||||
@@ -43,54 +42,28 @@ import { useNavigate } from 'react-router'
|
|||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
import JsonPreview from '@/components/admin/JsonPreview'
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
import ImageUpload from '@/components/files/ImageUpload'
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
acceptAdminWorkOrder,
|
||||||
acceptAdminWorkOrders,
|
acceptAdminWorkOrders,
|
||||||
assignAdminWorkOrderToWorker,
|
assignAdminWorkOrderToWorker,
|
||||||
cancelAdminWorkOrder,
|
cancelAdminWorkOrder,
|
||||||
createAdminMockWorkOrder,
|
createAdminMockWorkOrder,
|
||||||
creditAdminWorkerWallet,
|
|
||||||
deductAdminWorkOrderPendingDeposit,
|
deductAdminWorkOrderPendingDeposit,
|
||||||
deleteAdminWorkCategory,
|
|
||||||
deleteAdminWorkOrder,
|
deleteAdminWorkOrder,
|
||||||
deleteAdminWorkerLevel,
|
|
||||||
fetchAdminWorkerFinanceConfig,
|
|
||||||
fetchAdminWorkerFinanceRequests,
|
|
||||||
fetchAdminWorkCategories,
|
fetchAdminWorkCategories,
|
||||||
fetchAdminWorkOrderSharing,
|
fetchAdminWorkOrderSharing,
|
||||||
fetchAdminWorkProductRules,
|
|
||||||
fetchAdminWorkerLevels,
|
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
fetchAdminWorkerUsers,
|
||||||
fetchAdminWorkOrders,
|
fetchAdminWorkOrders,
|
||||||
markAdminWorkOrderProblem,
|
markAdminWorkOrderProblem,
|
||||||
pinAdminWorkOrder,
|
pinAdminWorkOrder,
|
||||||
publishAdminWorkOrder,
|
publishAdminWorkOrder,
|
||||||
reviewAdminWorkerFinanceRequest,
|
|
||||||
resolveAdminProblemWorkOrder,
|
resolveAdminProblemWorkOrder,
|
||||||
reviewAdminWorkerUser,
|
|
||||||
saveAdminWorkerFinanceConfig,
|
|
||||||
saveAdminWorkCategory,
|
|
||||||
saveAdminWorkProductRule,
|
|
||||||
saveAdminWorkerLevel,
|
|
||||||
submitAdminWorkOrderMaterial,
|
submitAdminWorkOrderMaterial,
|
||||||
unpublishAdminWorkOrder,
|
unpublishAdminWorkOrder,
|
||||||
updateAdminWorkOrder,
|
updateAdminWorkOrder,
|
||||||
updateAdminWorkOrderSharing,
|
updateAdminWorkOrderSharing,
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type { CollectField, UploadedFile, WorkOrder, WorkOrderShare } from '@/types/worker-platform'
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
|
||||||
WorkerFinanceRequest,
|
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import { hasAdminRole } from '@/utils/admin-auth'
|
import { hasAdminRole } from '@/utils/admin-auth'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||||
@@ -112,7 +85,6 @@ import {
|
|||||||
formatStatus,
|
formatStatus,
|
||||||
resolveSharingShareStatusColor,
|
resolveSharingShareStatusColor,
|
||||||
resolveStatusColor,
|
resolveStatusColor,
|
||||||
type DetailFieldItem,
|
|
||||||
} from './shared'
|
} from './shared'
|
||||||
|
|
||||||
const FILTERABLE_WORK_ORDER_STATUSES = [
|
const FILTERABLE_WORK_ORDER_STATUSES = [
|
||||||
@@ -1003,7 +975,7 @@ export default function WorkOrdersPanel() {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
const orderId = detailOrder.orderId
|
const orderId = detailOrder.orderId
|
||||||
setDetailOrder(null)
|
setDetailOrder(null)
|
||||||
navigate(`/admin/orders/${orderId}`)
|
void navigate(`/admin/orders/${orderId}`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
查看源订单
|
查看源订单
|
||||||
|
|||||||
@@ -1,83 +1,30 @@
|
|||||||
import {
|
import { ReloadOutlined } from '@ant-design/icons'
|
||||||
CheckOutlined,
|
|
||||||
FormOutlined,
|
|
||||||
PlusOutlined,
|
|
||||||
ReloadOutlined,
|
|
||||||
SendOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
TeamOutlined,
|
|
||||||
WarningOutlined,
|
|
||||||
} from '@ant-design/icons'
|
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Descriptions,
|
|
||||||
Drawer,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
|
||||||
Switch,
|
|
||||||
Table,
|
Table,
|
||||||
Tabs,
|
|
||||||
Tag,
|
Tag,
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
import JsonPreview from '@/components/admin/JsonPreview'
|
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
|
||||||
import {
|
import {
|
||||||
acceptAdminWorkOrder,
|
|
||||||
createAdminMockWorkOrder,
|
|
||||||
creditAdminWorkerWallet,
|
creditAdminWorkerWallet,
|
||||||
deleteAdminWorkCategory,
|
|
||||||
deleteAdminWorkerLevel,
|
|
||||||
fetchAdminWorkerFinanceConfig,
|
|
||||||
fetchAdminWorkerFinanceRequests,
|
|
||||||
fetchAdminWorkCategories,
|
|
||||||
fetchAdminWorkOrderSharing,
|
|
||||||
fetchAdminWorkProductRules,
|
|
||||||
fetchAdminWorkerLevels,
|
fetchAdminWorkerLevels,
|
||||||
fetchAdminWorkerPlatformSummary,
|
|
||||||
fetchAdminWorkerUsers,
|
fetchAdminWorkerUsers,
|
||||||
fetchAdminWorkOrders,
|
|
||||||
markAdminWorkOrderProblem,
|
|
||||||
publishAdminWorkOrder,
|
|
||||||
reviewAdminWorkerFinanceRequest,
|
|
||||||
resolveAdminProblemWorkOrder,
|
|
||||||
reviewAdminWorkerUser,
|
reviewAdminWorkerUser,
|
||||||
saveAdminWorkerFinanceConfig,
|
|
||||||
saveAdminWorkCategory,
|
|
||||||
saveAdminWorkProductRule,
|
|
||||||
saveAdminWorkerLevel,
|
|
||||||
submitAdminWorkOrderMaterial,
|
|
||||||
unpublishAdminWorkOrder,
|
|
||||||
updateAdminWorkOrderSharing,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type { WorkerUser } from '@/types/worker-platform'
|
||||||
CollectField,
|
|
||||||
UploadedFile,
|
|
||||||
WorkCategory,
|
|
||||||
WorkOrder,
|
|
||||||
WorkOrderShare,
|
|
||||||
WorkProductRule,
|
|
||||||
WorkerFinanceConfig,
|
|
||||||
WorkerFinanceRequest,
|
|
||||||
WorkerLevel,
|
|
||||||
WorkerUser,
|
|
||||||
} from '@/types/worker-platform'
|
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
|
||||||
import { formatMoney, formatWorkerStatus } from './shared'
|
import { formatMoney, formatWorkerStatus } from './shared'
|
||||||
|
|
||||||
export default function WorkersPanel() {
|
export default function WorkersPanel() {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Descriptions, Space, Tag, Typography } from 'antd'
|
import { Descriptions, Space, Tag, Typography } from 'antd'
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
||||||
import { DeadlineCountdown, formatTimeoutPolicyLabel } from '@/components/DeadlineCountdown'
|
import { DeadlineCountdown, formatTimeoutPolicyLabel } from '@/components/DeadlineCountdown'
|
||||||
import type { CollectField, UploadedFile, WorkOrder, WorkOrderShare } from '@/types/worker-platform'
|
import type { CollectField, UploadedFile, WorkOrder } from '@/types/worker-platform'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
|
||||||
|
|
||||||
export { DeadlineCountdown, formatTimeoutPolicyLabel }
|
export { DeadlineCountdown, formatTimeoutPolicyLabel }
|
||||||
|
|
||||||
|
|||||||
@@ -1368,7 +1368,7 @@ function resolveDefaultSourceKey(sourceRows: SourceRow[], selectedSourceKey: str
|
|||||||
function normalizeMatchName(value: unknown) {
|
function normalizeMatchName(value: unknown) {
|
||||||
return String(value || '')
|
return String(value || '')
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/[【】\[\]()()]/g, ' ')
|
.replace(/[【】[\]()()]/g, ' ')
|
||||||
.replace(/(自动发货|秒发|极速发货|官方直充|官方充值)/gi, ' ')
|
.replace(/(自动发货|秒发|极速发货|官方直充|官方充值)/gi, ' ')
|
||||||
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
.replace(/[^\p{L}\p{N}]+/gu, ' ')
|
||||||
.replace(/\s+/g, ' ')
|
.replace(/\s+/g, ' ')
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Select,
|
|
||||||
Space,
|
Space,
|
||||||
Spin,
|
Spin,
|
||||||
Switch,
|
Switch,
|
||||||
@@ -134,7 +133,7 @@ export default function AdminPlatformShopsPage() {
|
|||||||
const [feifeiConfig, setFeifeiConfig] = useState<AdminKuaishouFeifeiConfigResponse | null>(null)
|
const [feifeiConfig, setFeifeiConfig] = useState<AdminKuaishouFeifeiConfigResponse | null>(null)
|
||||||
const [cloudtentaclesConfig, setCloudtentaclesConfig] =
|
const [cloudtentaclesConfig, setCloudtentaclesConfig] =
|
||||||
useState<AdminCloudtentaclesSourceConfigResponse | null>(null)
|
useState<AdminCloudtentaclesSourceConfigResponse | null>(null)
|
||||||
const [affiliateDashConfig, setAffiliateDashConfig] =
|
const [_affiliateDashConfig, setAffiliateDashConfig] =
|
||||||
useState<AdminAffiliateDashConfigResponse | null>(null)
|
useState<AdminAffiliateDashConfigResponse | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -2930,7 +2929,9 @@ function AffiliateDashPlatformPanel() {
|
|||||||
current: productPage,
|
current: productPage,
|
||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
total: productTotal,
|
total: productTotal,
|
||||||
onChange: (page) => loadProducts(page),
|
onChange: (page) => {
|
||||||
|
void loadProducts(page)
|
||||||
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default function WorkerHallPage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!autoRefresh) return
|
if (!autoRefresh) return
|
||||||
const timer = window.setInterval(() => {
|
const timer = window.setInterval(() => {
|
||||||
refreshAll()
|
void refreshAll()
|
||||||
}, 5000)
|
}, 5000)
|
||||||
return () => window.clearInterval(timer)
|
return () => window.clearInterval(timer)
|
||||||
}, [autoRefresh])
|
}, [autoRefresh])
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default function WorkerLoginPage() {
|
|||||||
const response = await loginWorker(values)
|
const response = await loginWorker(values)
|
||||||
setWorkerSession(response.data.token, response.data.expiresAt, response.data.worker)
|
setWorkerSession(response.data.token, response.data.expiresAt, response.data.worker)
|
||||||
message.success('登录成功')
|
message.success('登录成功')
|
||||||
navigate('/hall', { replace: true })
|
void navigate('/hall', { replace: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error(error instanceof Error ? error.message : '登录失败')
|
message.error(error instanceof Error ? error.message : '登录失败')
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import {
|
|||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
AutoComplete,
|
|
||||||
App,
|
App,
|
||||||
Alert,
|
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Descriptions,
|
Descriptions,
|
||||||
@@ -29,7 +27,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useEffect, useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { DeadlineCountdown } from '@/components/DeadlineCountdown'
|
import { DeadlineCountdown } from '@/components/DeadlineCountdown'
|
||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
||||||
@@ -652,7 +650,7 @@ export default function WorkerOrdersPage() {
|
|||||||
)
|
)
|
||||||
const screenshots = getMaterialScreenshots(order)
|
const screenshots = getMaterialScreenshots(order)
|
||||||
const canCopyInfo = getCopyOrderInfoItems(order).length > 0
|
const canCopyInfo = getCopyOrderInfoItems(order).length > 0
|
||||||
const submittedAt = getAcceptanceSubmittedAt(order)
|
const _submittedAt = getAcceptanceSubmittedAt(order)
|
||||||
const acceptanceFiles = getUniqueAcceptanceFiles(getWorkerAcceptance(order))
|
const acceptanceFiles = getUniqueAcceptanceFiles(getWorkerAcceptance(order))
|
||||||
const hasAcceptance = acceptanceFiles.length > 0
|
const hasAcceptance = acceptanceFiles.length > 0
|
||||||
const draftFiles = getUniqueAcceptanceFiles(getWorkerDraft(order))
|
const draftFiles = getUniqueAcceptanceFiles(getWorkerDraft(order))
|
||||||
@@ -1409,28 +1407,6 @@ function getUniqueAcceptanceFiles(source?: WorkerAcceptance | null): UploadedFil
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAcceptanceFiles(row: WorkOrder): UploadedFile[] {
|
|
||||||
return getAcceptanceFilesFromSource(getWorkerAcceptance(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAcceptanceImageUrls(row: WorkOrder): string[] {
|
|
||||||
const imageUrls = getWorkerAcceptance(row)?.imageUrls
|
|
||||||
return Array.isArray(imageUrls)
|
|
||||||
? imageUrls.map((item) => String(item || '').trim()).filter(Boolean)
|
|
||||||
: []
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDraftFiles(row: WorkOrder): UploadedFile[] {
|
|
||||||
return getAcceptanceFilesFromSource(getWorkerDraft(row))
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDraftImageUrls(row: WorkOrder): string[] {
|
|
||||||
const imageUrls = getWorkerDraft(row)?.imageUrls
|
|
||||||
return Array.isArray(imageUrls)
|
|
||||||
? imageUrls.map((item) => String(item || '').trim()).filter(Boolean)
|
|
||||||
: []
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAcceptanceSubmittedAt(order: WorkOrder): string | null {
|
function getAcceptanceSubmittedAt(order: WorkOrder): string | null {
|
||||||
if (order.myShare) return order.myShare.submittedAt
|
if (order.myShare) return order.myShare.submittedAt
|
||||||
const acceptanceSubmittedAt =
|
const acceptanceSubmittedAt =
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ export default function WorkerProfilePage() {
|
|||||||
} finally {
|
} finally {
|
||||||
clearWorkerSession()
|
clearWorkerSession()
|
||||||
message.success('已退出登录')
|
message.success('已退出登录')
|
||||||
navigate('/', { replace: true })
|
void navigate('/', { replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ export default function WorkerProfilePage() {
|
|||||||
})
|
})
|
||||||
message.success('密码已修改,请重新登录')
|
message.success('密码已修改,请重新登录')
|
||||||
clearWorkerSession()
|
clearWorkerSession()
|
||||||
navigate('/', { replace: true })
|
void navigate('/', { replace: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error(error instanceof Error ? error.message : '修改密码失败')
|
message.error(error instanceof Error ? error.message : '修改密码失败')
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.app.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"noEmit": true,
|
||||||
|
"types": ["node"]
|
||||||
|
},
|
||||||
|
"include": ["src", "tests", "vite.config.ts"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user