feat(接单): 好友赠送冷却支持分钟单位
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
-- 064_work_order_gift_cooldown_minutes.sql —— 好友赠送冷却支持按分钟配置。
|
||||
-- 小时与分钟两种单位互斥;保留原小时字段,历史模板与工单自动沿用小时配置。
|
||||
|
||||
ALTER TABLE work_product_rules
|
||||
ADD COLUMN IF NOT EXISTS gift_cooldown_minutes INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE work_orders
|
||||
ADD COLUMN IF NOT EXISTS gift_cooldown_minutes INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
COMMENT ON COLUMN work_product_rules.gift_cooldown_minutes
|
||||
IS '好友赠送按分钟配置时的总分钟数(1-43200);非零时小时字段为 0,建单时拷贝到工单';
|
||||
|
||||
COMMENT ON COLUMN work_orders.gift_cooldown_minutes
|
||||
IS '好友赠送按分钟配置时的总分钟数(1-43200);非零时小时字段为 0,从模板拷贝';
|
||||
@@ -4,6 +4,8 @@ import assert from 'node:assert/strict'
|
||||
import {
|
||||
isWorkOrderGiftDepositForfeitable,
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
resolveWorkOrderGiftPhase,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
WORK_ORDER_GIFT_PHASE,
|
||||
@@ -58,3 +60,10 @@ test('赠送阶段按冷却到点实时推导 gift_ready', () => {
|
||||
assert.equal(normalizeWorkOrderAcceptanceMode('friend_gift'), 'friend_gift')
|
||||
assert.equal(normalizeWorkOrderAcceptanceMode(''), 'standard')
|
||||
})
|
||||
|
||||
test('好友赠送按分钟冷却支持最长三十天并忽略负数', () => {
|
||||
assert.equal(normalizeWorkOrderGiftCooldownHours(0), 0)
|
||||
assert.equal(normalizeWorkOrderGiftCooldownMinutes(15), 15)
|
||||
assert.equal(normalizeWorkOrderGiftCooldownMinutes(43_201), 43_200)
|
||||
assert.equal(normalizeWorkOrderGiftCooldownMinutes(-1), 0)
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ export type WorkOrderAcceptanceMode =
|
||||
|
||||
export const DEFAULT_GIFT_COOLDOWN_HOURS = 72
|
||||
export const MAX_GIFT_COOLDOWN_HOURS = 24 * 30
|
||||
export const MAX_GIFT_COOLDOWN_MINUTES = MAX_GIFT_COOLDOWN_HOURS * 60
|
||||
|
||||
/** 好友赠送模式的落库阶段;gift_ready 由 gift_available_at 到点后实时计算,不落库。 */
|
||||
export const WORK_ORDER_GIFT_PHASE = {
|
||||
@@ -33,11 +34,18 @@ export function isFriendGiftAcceptanceMode(value: unknown): boolean {
|
||||
return normalizeWorkOrderAcceptanceMode(value) === WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT
|
||||
}
|
||||
|
||||
/** 冷却小时数收敛到 [0, 30 天],默认 3 天。 */
|
||||
/** 冷却小时数收敛到 [0, 30 天],默认 3 天。0 用于选择按分钟配置。 */
|
||||
export function normalizeWorkOrderGiftCooldownHours(value: unknown): number {
|
||||
const hours = Number(value)
|
||||
if (!Number.isFinite(hours) || hours <= 0) return DEFAULT_GIFT_COOLDOWN_HOURS
|
||||
return Math.min(MAX_GIFT_COOLDOWN_HOURS, Math.max(1, Math.round(hours)))
|
||||
if (!Number.isFinite(hours) || hours < 0) return DEFAULT_GIFT_COOLDOWN_HOURS
|
||||
return Math.min(MAX_GIFT_COOLDOWN_HOURS, Math.round(hours))
|
||||
}
|
||||
|
||||
/** 按分钟配置时的总分钟数,最大 30 天。 */
|
||||
export function normalizeWorkOrderGiftCooldownMinutes(value: unknown): number {
|
||||
const minutes = Number(value)
|
||||
if (!Number.isFinite(minutes)) return 0
|
||||
return Math.min(MAX_GIFT_COOLDOWN_MINUTES, Math.max(0, Math.round(minutes)))
|
||||
}
|
||||
|
||||
export type WorkOrderGiftSource = {
|
||||
|
||||
@@ -270,6 +270,7 @@ export type WorkProductRuleRow = {
|
||||
timeout_policy: string
|
||||
acceptance_mode: string
|
||||
gift_cooldown_hours: number
|
||||
gift_cooldown_minutes: number
|
||||
requirement_json: string | Record<string, unknown>
|
||||
match_json: string | Record<string, unknown>
|
||||
sort_order: number
|
||||
@@ -378,6 +379,7 @@ export type WorkOrderRow = {
|
||||
friend_added_at: string | null
|
||||
gift_available_at: string | null
|
||||
gift_cooldown_hours: number
|
||||
gift_cooldown_minutes: number
|
||||
created_at: string
|
||||
updated_at: string
|
||||
/** 拼单聚合字段,由工单查询统一计算。 */
|
||||
@@ -546,6 +548,7 @@ export type CreateWorkOrderInput = {
|
||||
timeoutPolicy?: string
|
||||
acceptanceMode?: string
|
||||
giftCooldownHours?: number
|
||||
giftCooldownMinutes?: number
|
||||
materialJson: string
|
||||
requirementJson: string
|
||||
now: string
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { WorkOrderRow } from './types.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
WORK_ORDER_GIFT_PHASE,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
@@ -121,6 +122,7 @@ export async function confirmWorkOrderFriendAdded(input: {
|
||||
}
|
||||
|
||||
const cooldownHours = normalizeWorkOrderGiftCooldownHours(workOrder.gift_cooldown_hours)
|
||||
const cooldownMinutes = normalizeWorkOrderGiftCooldownMinutes(workOrder.gift_cooldown_minutes)
|
||||
// 参数必须显式转型:未知类型参数与 interval 做运算时 PostgreSQL 无法唯一解析操作符。
|
||||
await client.query(
|
||||
`
|
||||
@@ -128,16 +130,16 @@ export async function confirmWorkOrderFriendAdded(input: {
|
||||
SET
|
||||
gift_phase = 'friend_countdown',
|
||||
friend_added_at = $1::timestamptz,
|
||||
gift_available_at = $1::timestamptz + ($2::int * INTERVAL '1 hour'),
|
||||
gift_available_at = $1::timestamptz + ($2::int * INTERVAL '1 hour') + ($3::int * INTERVAL '1 minute'),
|
||||
deadline_at = CASE
|
||||
WHEN timeout_minutes > 0
|
||||
THEN $1::timestamptz + ($2::int * INTERVAL '1 hour') + (timeout_minutes * INTERVAL '1 minute')
|
||||
THEN $1::timestamptz + ($2::int * INTERVAL '1 hour') + ($3::int * INTERVAL '1 minute') + (timeout_minutes * INTERVAL '1 minute')
|
||||
ELSE NULL
|
||||
END,
|
||||
updated_at = $1::timestamptz
|
||||
WHERE id = $3
|
||||
WHERE id = $4
|
||||
`,
|
||||
[input.now, cooldownHours, input.workOrderId],
|
||||
[input.now, cooldownHours, cooldownMinutes, input.workOrderId],
|
||||
)
|
||||
await createWorkOrderEventWithClient(client, {
|
||||
workOrderId: input.workOrderId,
|
||||
@@ -148,6 +150,7 @@ export async function confirmWorkOrderFriendAdded(input: {
|
||||
toStatus: workOrder.status,
|
||||
payloadJson: JSON.stringify({
|
||||
cooldownHours,
|
||||
cooldownMinutes,
|
||||
friendAddedAt: input.now,
|
||||
}),
|
||||
now: input.now,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getWorkOrderById } from './work-order-query-repo.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
WORK_ORDER_GIFT_PHASE,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
@@ -19,13 +20,13 @@ export async function createWorkOrder(input: CreateWorkOrderInput): Promise<Work
|
||||
product_name, category_id, status, reward_amount, required_deposit_amount,
|
||||
deposit_threshold_amount, sharing_enabled, sharing_total_quantity,
|
||||
sharing_unit_reward, timeout_minutes, timeout_policy,
|
||||
acceptance_mode, gift_phase, gift_cooldown_hours,
|
||||
acceptance_mode, gift_phase, gift_cooldown_hours, gift_cooldown_minutes,
|
||||
material_json, requirement_json, created_at, updated_at
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
|
||||
$12, $13, $14, $15, $16, $17,
|
||||
$18, $19, $20,
|
||||
$21::jsonb, $22::jsonb, $23, $24
|
||||
$18, $19, $20, $21,
|
||||
$22::jsonb, $23::jsonb, $24, $25
|
||||
)
|
||||
RETURNING id
|
||||
`,
|
||||
@@ -50,6 +51,7 @@ export async function createWorkOrder(input: CreateWorkOrderInput): Promise<Work
|
||||
acceptanceMode,
|
||||
isFriendGift ? WORK_ORDER_GIFT_PHASE.MATERIAL_REQUIRED : '',
|
||||
normalizeWorkOrderGiftCooldownHours(input.giftCooldownHours),
|
||||
normalizeWorkOrderGiftCooldownMinutes(input.giftCooldownMinutes),
|
||||
input.materialJson,
|
||||
input.requirementJson,
|
||||
input.now,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { toPositiveInteger } from './shared.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import type {
|
||||
ProductRuleListInput,
|
||||
@@ -342,6 +343,7 @@ export async function upsertWorkProductRule(input: {
|
||||
timeoutPolicy?: string
|
||||
acceptanceMode?: string
|
||||
giftCooldownHours?: number
|
||||
giftCooldownMinutes?: number
|
||||
requirementJson: string
|
||||
matchJson?: string
|
||||
sortOrder: number
|
||||
@@ -356,7 +358,7 @@ export async function upsertWorkProductRule(input: {
|
||||
required_deposit_amount, deposit_threshold_amount,
|
||||
sharing_enabled, sharing_total_quantity, sharing_unit_reward, sharing_auto_from_order,
|
||||
timeout_minutes, timeout_policy,
|
||||
acceptance_mode, gift_cooldown_hours,
|
||||
acceptance_mode, gift_cooldown_hours, gift_cooldown_minutes,
|
||||
requirement_json, match_json,
|
||||
sort_order, created_at, updated_at
|
||||
) VALUES (
|
||||
@@ -366,9 +368,9 @@ export async function upsertWorkProductRule(input: {
|
||||
$13, $14,
|
||||
$15, $16, $17, $18,
|
||||
$19, $20,
|
||||
$21, $22,
|
||||
$23::jsonb, $24::jsonb,
|
||||
$25, $26, $27
|
||||
$21, $22, $23,
|
||||
$24::jsonb, $25::jsonb,
|
||||
$26, $27, $28
|
||||
)
|
||||
ON CONFLICT (rule_key) DO UPDATE
|
||||
SET
|
||||
@@ -393,6 +395,7 @@ export async function upsertWorkProductRule(input: {
|
||||
timeout_policy = EXCLUDED.timeout_policy,
|
||||
acceptance_mode = EXCLUDED.acceptance_mode,
|
||||
gift_cooldown_hours = EXCLUDED.gift_cooldown_hours,
|
||||
gift_cooldown_minutes = EXCLUDED.gift_cooldown_minutes,
|
||||
requirement_json = EXCLUDED.requirement_json,
|
||||
match_json = EXCLUDED.match_json,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
@@ -422,6 +425,7 @@ export async function upsertWorkProductRule(input: {
|
||||
String(input.timeoutPolicy || 'reopen').trim(),
|
||||
normalizeWorkOrderAcceptanceMode(input.acceptanceMode),
|
||||
normalizeWorkOrderGiftCooldownHours(input.giftCooldownHours),
|
||||
normalizeWorkOrderGiftCooldownMinutes(input.giftCooldownMinutes),
|
||||
input.requirementJson,
|
||||
input.matchJson || '{}',
|
||||
input.sortOrder,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import {
|
||||
createWorkOrder,
|
||||
@@ -114,6 +115,7 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
|
||||
timeoutPolicy: normalizeWorkOrderTimeoutPolicy(payload.timeoutPolicy),
|
||||
acceptanceMode: normalizeWorkOrderAcceptanceMode(payload.acceptanceMode),
|
||||
giftCooldownHours: normalizeWorkOrderGiftCooldownHours(payload.giftCooldownHours),
|
||||
giftCooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(payload.giftCooldownMinutes),
|
||||
materialJson: JSON.stringify(material),
|
||||
requirementJson: JSON.stringify({ fields }),
|
||||
now,
|
||||
|
||||
@@ -26,6 +26,7 @@ import type { WorkOrderRow, WorkProductRuleRow } from '../../repositories/worker
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
@@ -374,6 +375,13 @@ export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
|
||||
payload.giftCooldownHours ?? payload.gift_cooldown_hours,
|
||||
)
|
||||
: normalizeWorkOrderGiftCooldownHours(existingRule?.gift_cooldown_hours),
|
||||
giftCooldownMinutes:
|
||||
hasOwnPayload(payload, 'giftCooldownMinutes') ||
|
||||
hasOwnPayload(payload, 'gift_cooldown_minutes')
|
||||
? normalizeWorkOrderGiftCooldownMinutes(
|
||||
payload.giftCooldownMinutes ?? payload.gift_cooldown_minutes,
|
||||
)
|
||||
: normalizeWorkOrderGiftCooldownMinutes(existingRule?.gift_cooldown_minutes),
|
||||
requirementJson: JSON.stringify({ fields }),
|
||||
matchJson: JSON.stringify(match),
|
||||
sortOrder: normalizeInteger(payload.sortOrder, 100),
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
isFriendGiftAcceptanceMode,
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import {
|
||||
createWorkProductMatchLog,
|
||||
@@ -138,6 +139,7 @@ export async function syncWorkerOrdersForSourceOrder(
|
||||
timeoutPolicy: String(rule.timeout_policy || 'reopen').trim(),
|
||||
acceptanceMode: normalizeWorkOrderAcceptanceMode(rule.acceptance_mode),
|
||||
giftCooldownHours: normalizeWorkOrderGiftCooldownHours(rule.gift_cooldown_hours),
|
||||
giftCooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(rule.gift_cooldown_minutes),
|
||||
materialJson: JSON.stringify({
|
||||
source: {
|
||||
orderId: Number(order.id),
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
isFriendGiftAcceptanceMode,
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
resolveWorkOrderGiftPhase,
|
||||
WORK_ORDER_ACCEPTANCE_MODE,
|
||||
WORK_ORDER_GIFT_PHASE,
|
||||
@@ -212,6 +213,7 @@ export function mapWorkOrderAdmin(workOrder: WorkOrderRow, shares?: WorkOrderSha
|
||||
phase: resolveWorkOrderGiftPhase(workOrder),
|
||||
rawPhase: giftPhase,
|
||||
cooldownHours: normalizeWorkOrderGiftCooldownHours(workOrder.gift_cooldown_hours),
|
||||
cooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(workOrder.gift_cooldown_minutes),
|
||||
friendAddedAt: workOrder.friend_added_at,
|
||||
giftAvailableAt: workOrder.gift_available_at,
|
||||
boosterMaterial: mapWorkOrderBoosterMaterial(workOrder.booster_material_json),
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
import {
|
||||
normalizeWorkOrderAcceptanceMode,
|
||||
normalizeWorkOrderGiftCooldownHours,
|
||||
normalizeWorkOrderGiftCooldownMinutes,
|
||||
} from '../../domain/work-order-acceptance-mode.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||
@@ -51,6 +52,7 @@ export function mapWorkProductRule(rule: WorkProductRuleRow | null | undefined)
|
||||
timeoutPolicy: String(rule.timeout_policy || 'reopen').trim(),
|
||||
acceptanceMode: normalizeWorkOrderAcceptanceMode(rule.acceptance_mode),
|
||||
giftCooldownHours: normalizeWorkOrderGiftCooldownHours(rule.gift_cooldown_hours),
|
||||
giftCooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(rule.gift_cooldown_minutes),
|
||||
requirement: {
|
||||
fields: normalizeRequirementFields(requirement.fields),
|
||||
},
|
||||
|
||||
@@ -209,7 +209,11 @@ export default function ProductRulesPanel() {
|
||||
timeoutMinutes: rule.timeoutMinutes || 0,
|
||||
timeoutPolicy: rule.timeoutPolicy || 'reopen',
|
||||
acceptanceMode: rule.acceptanceMode || 'standard',
|
||||
giftCooldownHours: rule.giftCooldownHours || 72,
|
||||
giftCooldownUnit: Number(rule.giftCooldownMinutes || 0) > 0 ? 'minutes' : 'hours',
|
||||
giftCooldownValue:
|
||||
Number(rule.giftCooldownMinutes || 0) > 0
|
||||
? Number(rule.giftCooldownMinutes || 0)
|
||||
: Number(rule.giftCooldownHours ?? 72),
|
||||
fieldsText: formatRuleFields(rule.requirement?.fields || []),
|
||||
sortOrder: rule.sortOrder,
|
||||
enabled: rule.enabled,
|
||||
@@ -247,7 +251,8 @@ export default function ProductRulesPanel() {
|
||||
timeoutMinutes?: number
|
||||
timeoutPolicy?: string
|
||||
acceptanceMode?: string
|
||||
giftCooldownHours?: number
|
||||
giftCooldownUnit?: 'hours' | 'minutes'
|
||||
giftCooldownValue?: number
|
||||
fieldsText?: string
|
||||
enabled?: boolean
|
||||
autoCreate?: boolean
|
||||
@@ -265,13 +270,17 @@ export default function ProductRulesPanel() {
|
||||
? Number(values.sharingTotalQuantity || 0) > 0 ||
|
||||
Number(values.sharingUnitReward || 0) > 0
|
||||
: hasManualSharingInput(values.sharingTotalQuantity, values.sharingUnitReward)
|
||||
const { pricingMode: _pricingMode, ...payload } = values
|
||||
const { pricingMode: _pricingMode, giftCooldownUnit, giftCooldownValue, ...payload } = values
|
||||
const res = await saveAdminWorkProductRule({
|
||||
...payload,
|
||||
ruleId: editingRule?.ruleId,
|
||||
ruleKey: editingRule?.ruleKey || '',
|
||||
unitPrice: unitMode ? Number(values.unitPrice || 0) : 0,
|
||||
acceptanceMode: isFriendGift ? 'friend_gift' : 'standard',
|
||||
giftCooldownHours:
|
||||
isFriendGift && giftCooldownUnit !== 'minutes' ? Number(giftCooldownValue || 0) : 0,
|
||||
giftCooldownMinutes:
|
||||
isFriendGift && giftCooldownUnit === 'minutes' ? Number(giftCooldownValue || 0) : 0,
|
||||
sharingEnabled: isFriendGift ? false : values.sharingEnabled === true,
|
||||
sharingAutoFromOrder:
|
||||
unitMode && values.sharingEnabled === true && !hasManualSharingOverride,
|
||||
@@ -745,7 +754,8 @@ export default function ProductRulesPanel() {
|
||||
autoCreate: true,
|
||||
sharingEnabled: false,
|
||||
acceptanceMode: 'standard',
|
||||
giftCooldownHours: 72,
|
||||
giftCooldownUnit: 'hours',
|
||||
giftCooldownValue: 72,
|
||||
fieldsText:
|
||||
'gameId:游戏编号\ngameNickname:游戏昵称\nsystem:系统#安卓,苹果\nserverZone:区服#QQ区,微信区',
|
||||
}}
|
||||
@@ -838,19 +848,47 @@ export default function ProductRulesPanel() {
|
||||
<Form.Item noStyle shouldUpdate>
|
||||
{({ getFieldValue }) =>
|
||||
getFieldValue('acceptanceMode') === 'friend_gift' ? (
|
||||
<Form.Item
|
||||
label="赠送冷却"
|
||||
name="giftCooldownHours"
|
||||
rules={[{ required: true, message: '请填写冷却小时数' }]}
|
||||
extra="确认加好友后需冷却该时长才能赠送(默认 72 小时 = 3 天)"
|
||||
>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={720}
|
||||
step={1}
|
||||
addonAfter="小时"
|
||||
className="full-width"
|
||||
/>
|
||||
<Form.Item label="赠送冷却" required>
|
||||
<Space.Compact className="full-width">
|
||||
<Form.Item name="giftCooldownUnit" noStyle>
|
||||
<Select
|
||||
style={{ width: 100 }}
|
||||
options={[
|
||||
{ value: 'hours', label: '按小时' },
|
||||
{ value: 'minutes', label: '按分钟' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
noStyle
|
||||
shouldUpdate={(previous, current) =>
|
||||
previous.giftCooldownUnit !== current.giftCooldownUnit
|
||||
}
|
||||
>
|
||||
{({ getFieldValue }) => {
|
||||
const unit = getFieldValue('giftCooldownUnit')
|
||||
const isMinutes = unit === 'minutes'
|
||||
return (
|
||||
<Form.Item
|
||||
name="giftCooldownValue"
|
||||
noStyle
|
||||
rules={[{ required: true, message: '请填写冷却时长' }]}
|
||||
>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={isMinutes ? 43200 : 720}
|
||||
step={1}
|
||||
addonAfter={isMinutes ? '分钟' : '小时'}
|
||||
className="full-width"
|
||||
/>
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
</Form.Item>
|
||||
</Space.Compact>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
选择小时或分钟其中一种单位;最长 30 天(720 小时 / 43200 分钟)。
|
||||
</Typography.Text>
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item label={<span />} />
|
||||
|
||||
@@ -861,6 +861,8 @@ export default function WorkOrdersPanel() {
|
||||
|
||||
function confirmFriendAdded(row: WorkOrder) {
|
||||
const cooldownHours = Number(row.gift?.cooldownHours || 72)
|
||||
const cooldownMinutes = Number(row.gift?.cooldownMinutes || 0)
|
||||
const cooldownLabel = cooldownMinutes > 0 ? `${cooldownMinutes} 分钟` : `${cooldownHours} 小时`
|
||||
modal.confirm({
|
||||
title: '确认已添加打手为游戏好友?',
|
||||
content: (
|
||||
@@ -869,8 +871,8 @@ export default function WorkOrdersPanel() {
|
||||
请先核对打手提交的昵称 / ID / 区服与主页截图,确认已在游戏内互为好友后再点击确认。
|
||||
</Typography.Paragraph>
|
||||
<Typography.Paragraph>
|
||||
确认后开始 {cooldownHours}{' '}
|
||||
小时赠送冷却,冷却结束前打手不能提交赠送凭证;任务时限将顺延到冷却结束后重新起算。
|
||||
确认后开始 {cooldownLabel}
|
||||
赠送冷却,冷却结束前打手不能提交赠送凭证;任务时限将顺延到冷却结束后重新起算。
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
),
|
||||
@@ -879,7 +881,7 @@ export default function WorkOrdersPanel() {
|
||||
onOk: () =>
|
||||
runAction(
|
||||
() => confirmAdminWorkOrderFriend(row.workOrderId),
|
||||
`已确认加好友,${cooldownHours} 小时冷却开始`,
|
||||
`已确认加好友,${cooldownLabel} 冷却开始`,
|
||||
),
|
||||
})
|
||||
}
|
||||
@@ -1652,7 +1654,9 @@ export default function WorkOrdersPanel() {
|
||||
<div className="worker-order-detail-stack">
|
||||
<Descriptions column={{ xs: 1, md: 2 }} bordered size="small">
|
||||
<Descriptions.Item label="冷却时长">
|
||||
{detailOrder.gift.cooldownHours} 小时
|
||||
{detailOrder.gift.cooldownMinutes > 0
|
||||
? `${detailOrder.gift.cooldownMinutes} 分钟`
|
||||
: `${detailOrder.gift.cooldownHours} 小时`}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="打手资料提交">
|
||||
{formatAdminDateTime(detailOrder.gift.boosterMaterial?.submittedAt)}
|
||||
@@ -2399,20 +2403,20 @@ export default function WorkOrdersPanel() {
|
||||
) : (
|
||||
<Typography.Text type="secondary">待提交</Typography.Text>
|
||||
)}
|
||||
{canCancelShare ? (
|
||||
<Button
|
||||
danger
|
||||
size="small"
|
||||
icon={<UndoOutlined />}
|
||||
title="只撤销当前参与者的拼单份额,其他参与者不受影响"
|
||||
onClick={() => {
|
||||
setCancelShare(share)
|
||||
cancelShareForm.setFieldsValue({ reason: '' })
|
||||
}}
|
||||
>
|
||||
单人撤单
|
||||
</Button>
|
||||
) : null}
|
||||
{canCancelShare ? (
|
||||
<Button
|
||||
danger
|
||||
size="small"
|
||||
icon={<UndoOutlined />}
|
||||
title="只撤销当前参与者的拼单份额,其他参与者不受影响"
|
||||
onClick={() => {
|
||||
setCancelShare(share)
|
||||
cancelShareForm.setFieldsValue({ reason: '' })
|
||||
}}
|
||||
>
|
||||
单人撤单
|
||||
</Button>
|
||||
) : null}
|
||||
</Space>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -207,7 +207,11 @@ function GiftProgressCard({ order }: { order: WorkOrder }) {
|
||||
]}
|
||||
/>
|
||||
<Descriptions column={{ xs: 1, md: 2 }} bordered size="small">
|
||||
<Descriptions.Item label="冷却时长">{gift.cooldownHours} 小时</Descriptions.Item>
|
||||
<Descriptions.Item label="冷却时长">
|
||||
{gift.cooldownMinutes > 0
|
||||
? `${gift.cooldownMinutes} 分钟`
|
||||
: `${gift.cooldownHours} 小时`}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="已加好友">
|
||||
{formatDateTime(gift.friendAddedAt)}
|
||||
</Descriptions.Item>
|
||||
|
||||
@@ -251,6 +251,7 @@ export function saveAdminWorkProductRule(payload: {
|
||||
timeoutPolicy?: string
|
||||
acceptanceMode?: 'standard' | 'friend_gift' | string
|
||||
giftCooldownHours?: number
|
||||
giftCooldownMinutes?: number
|
||||
fieldsText?: string
|
||||
sortOrder?: number
|
||||
}) {
|
||||
|
||||
@@ -376,6 +376,8 @@ export type WorkProductRule = {
|
||||
acceptanceMode?: 'standard' | 'friend_gift' | string
|
||||
/** 好友赠送冷却小时数(默认 72) */
|
||||
giftCooldownHours?: number
|
||||
/** 好友赠送按分钟配置时的总分钟数;非零时使用分钟单位。 */
|
||||
giftCooldownMinutes?: number
|
||||
sortOrder: number
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
@@ -514,6 +516,7 @@ export type WorkOrderGiftProgress = {
|
||||
phase: WorkOrderGiftPhase
|
||||
rawPhase: string
|
||||
cooldownHours: number
|
||||
cooldownMinutes: number
|
||||
friendAddedAt: string | null
|
||||
giftAvailableAt: string | null
|
||||
boosterMaterial: BoosterMaterial
|
||||
|
||||
Reference in New Issue
Block a user