feat(huya): 礼包名默认空白,改用「常用礼包」备选按钮
新建协作单以前会把「上次选的礼包」自动填进礼包名(localStorage huya.collab.lastGift)。连开几单同一个礼包是省事,但每开一单都顶着上一次的 选择,稍不留神就按错礼包建单;而且这个自动值会被草稿自动保存吃进去, 下次打开又「恢复」出来。 - 新建弹窗**不再预填礼包名**:删掉 lastGift 的读写,字段默认空白。 - 草稿恢复只带订单号 / 店铺 / CK / 截图 / 备注,礼包名留空; hasDraftContent() 也不再认「只有礼包名」的草稿(否则被旧逻辑自动填过的 那份草稿会一直弹「已恢复上次未提交的草稿」)。 - 新增 GET /external-orders/gifts/frequent:按台账里的使用次数排序 (次数相同看最近一次使用),新建与补资料弹窗在字段上方渲染最多 6 个按钮, 只显示**当前礼包缓存里还有的**(活动换 SID 后老礼包会整批下架)。 - 新增 5 例测试,并做了 3 次反向验证(去掉次数排序 / 改成升序 / 去掉空名过滤)。 补资料弹窗的初值仍是「这一单自己的礼包」,详情抽屉编辑也不动 —— 那不是 「上次选的」。
This commit is contained in:
@@ -39,6 +39,7 @@ import type {
|
||||
HuyaCollabCkPreview,
|
||||
HuyaCollabCkRequest,
|
||||
HuyaCollabCkStatusRequest,
|
||||
HuyaCollabFrequentGift,
|
||||
HuyaCollabImagesRequest,
|
||||
HuyaCollabImportResult,
|
||||
HuyaCollabMetric,
|
||||
@@ -212,6 +213,16 @@ export const huyaApi = {
|
||||
collabOrderShops: () => api.get<string[], string[]>('/huya/external-orders/shops'),
|
||||
/** 已用过的礼包/皮肤名(筛选下拉) */
|
||||
collabOrderGifts: () => api.get<string[], string[]>('/huya/external-orders/gifts'),
|
||||
/**
|
||||
* 常用礼包(台账里用得最多的几个):新建/补资料的礼包名快捷按钮。
|
||||
*
|
||||
* 只来自历史记录,**是不是当前活动还在卖的**由页面拿礼包缓存比对后决定要不要显示。
|
||||
*/
|
||||
collabFrequentGifts: (limit = 8) =>
|
||||
api.get<HuyaCollabFrequentGift[], HuyaCollabFrequentGift[]>(
|
||||
'/huya/external-orders/gifts/frequent',
|
||||
{ params: { limit } },
|
||||
),
|
||||
|
||||
// ---- 店铺字典(新建协作单时点选;见业务规则 docs/设计-虎牙外部CK协作台账.md)----
|
||||
/** 全部店铺(含停用的:管理弹窗要看到;新建下拉由页面按 is_active 过滤) */
|
||||
|
||||
@@ -1597,6 +1597,17 @@ export interface HuyaCollabGift {
|
||||
icon: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 「常用礼包」:台账里用得最多的礼包名 + 用过几次。
|
||||
*
|
||||
* 只来自历史记录;**当前活动还有没有它**要拿 `HuyaCollabGift` 缓存比对
|
||||
* (活动换 SID 后整批礼包会变,见设计文档 §11.4)。
|
||||
*/
|
||||
export interface HuyaCollabFrequentGift {
|
||||
name: string;
|
||||
used: number;
|
||||
}
|
||||
|
||||
/** 粘贴 CK 后的即时预览:ok 且 has_role 才允许提交新建 */
|
||||
export interface HuyaCollabCkPreview {
|
||||
ok: boolean;
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
type HuyaCollabAuditItem,
|
||||
type HuyaCollabCkExportResult,
|
||||
type HuyaCollabCkPreview,
|
||||
type HuyaCollabFrequentGift,
|
||||
type HuyaCollabGift,
|
||||
type HuyaCollabImageSlot,
|
||||
type HuyaCollabMetric,
|
||||
@@ -150,8 +151,6 @@ const SLOT_META: Record<HuyaCollabImageSlot, { label: string; keysKey: 'bind_ima
|
||||
};
|
||||
|
||||
const IMPORT_PREVIEW_ROWS = 20;
|
||||
// 「记住最近选的礼包」的本地存储键(同一个礼包连开几单时不用反复选)
|
||||
const LAST_GIFT_KEY = 'huya.collab.lastGift';
|
||||
// 「礼包列表」的本地缓存键:一个活动期间就那一批礼包,没必要每贴一份 CK 都去虎牙拉一次;
|
||||
// 要更新就点「强制刷新礼包」(活动换 SID 后必点一次)。
|
||||
const GIFTS_CACHE_KEY = 'huya.collab.gifts';
|
||||
@@ -258,11 +257,12 @@ function markDraftHintShown(): void {
|
||||
}
|
||||
|
||||
function hasDraftContent(draft: Omit<CreateDraft, 'saved_at'>): boolean {
|
||||
// 礼包名不算「填过东西」:它现在默认空白、也不从草稿恢复(见下面 createForm 那段的说明),
|
||||
// 否则一份「只被上次自动填了礼包」的老草稿会一直弹「已恢复上次未提交的草稿」。
|
||||
return Boolean(
|
||||
draft.order_no.trim()
|
||||
|| draft.shop.trim()
|
||||
|| draft.ck_text.trim()
|
||||
|| draft.gift_name.trim()
|
||||
|| draft.remark.trim()
|
||||
|| draft.home_images.length,
|
||||
);
|
||||
@@ -486,6 +486,8 @@ export default function HuyaCollabPage() {
|
||||
const [owners, setOwners] = useState<HuyaCollabOwner[]>([]);
|
||||
const [shops, setShops] = useState<HuyaCollabShop[]>([]);
|
||||
const [giftNames, setGiftNames] = useState<string[]>([]);
|
||||
// 「常用礼包」:台账里用得最多的几个(新建/补资料的礼包名快捷按钮,见 2026-10-18 需求)
|
||||
const [frequentGifts, setFrequentGifts] = useState<HuyaCollabFrequentGift[]>([]);
|
||||
const [shopModalOpen, setShopModalOpen] = useState(false);
|
||||
const [filters, setFilters] = useState<HuyaCollabOrderQuery>({ include_void: false });
|
||||
// 默认按固定创建序号正序:老单在上、新单永远追加在最后。
|
||||
@@ -564,7 +566,14 @@ export default function HuyaCollabPage() {
|
||||
const withMeta = options?.withMeta !== false;
|
||||
if (!silent) setLoading(true);
|
||||
try {
|
||||
const [list, nextSummary, nextOwners, nextShops, nextGiftNames] = await Promise.all([
|
||||
const [
|
||||
list,
|
||||
nextSummary,
|
||||
nextOwners,
|
||||
nextShops,
|
||||
nextGiftNames,
|
||||
nextFrequentGifts,
|
||||
] = await Promise.all([
|
||||
huyaApi.listCollabOrders({
|
||||
...filters,
|
||||
sort_by: sortKey,
|
||||
@@ -576,6 +585,7 @@ export default function HuyaCollabPage() {
|
||||
withMeta ? huyaApi.collabOrderOwners() : Promise.resolve(null),
|
||||
withMeta ? huyaApi.listCollabShops() : Promise.resolve(null),
|
||||
withMeta ? huyaApi.collabOrderGifts() : Promise.resolve(null),
|
||||
withMeta ? huyaApi.collabFrequentGifts() : Promise.resolve(null),
|
||||
]);
|
||||
setRows(list.items);
|
||||
setTotal(list.total);
|
||||
@@ -583,6 +593,7 @@ export default function HuyaCollabPage() {
|
||||
if (nextOwners) setOwners(nextOwners);
|
||||
if (nextShops) setShops(nextShops);
|
||||
if (nextGiftNames) setGiftNames(nextGiftNames);
|
||||
if (nextFrequentGifts) setFrequentGifts(nextFrequentGifts);
|
||||
// 选中是「当前页」的概念:刷新后剔除已经不在这页上的行,避免点到别人的脏 id。
|
||||
setSelectedIds((ids) => ids.filter((id) => list.items.some((row) => row.id === id)));
|
||||
} catch (e: unknown) {
|
||||
@@ -1446,7 +1457,6 @@ export default function HuyaCollabPage() {
|
||||
draft,
|
||||
require_verified: !draft, // 草稿单不跑探针;完整建单仍要求 CK 读到绑定角色
|
||||
});
|
||||
if (created.gift_name) window.localStorage.setItem(LAST_GIFT_KEY, created.gift_name);
|
||||
if (draft) {
|
||||
const reason = missing.length > 0
|
||||
? `还缺 ${missing.join('、')}`
|
||||
@@ -1543,6 +1553,50 @@ export default function HuyaCollabPage() {
|
||||
return options;
|
||||
};
|
||||
|
||||
/**
|
||||
* 「常用礼包」快捷按钮(2026-10-18 用户要求):
|
||||
* 礼包名**默认空白**(不再自动带上次选的那个,避免没注意时建错单),
|
||||
* 想少点两下就点这里的备选。
|
||||
*
|
||||
* 只列**当前礼包缓存里还有的**那几个:活动换 SID 之后老礼包基本都下架了,
|
||||
* 点一个拉不到的名字等于白点(见设计文档 §11.4)。缓存为空时整行不显示。
|
||||
*/
|
||||
const frequentGiftChoices = (): HuyaCollabFrequentGift[] => {
|
||||
if (giftOptions.length === 0) return [];
|
||||
const available = new Set(giftOptions.map((gift) => gift.name));
|
||||
return frequentGifts.filter((item) => available.has(item.name)).slice(0, 6);
|
||||
};
|
||||
|
||||
/** 按钮上的短标签:礼包名很长(「[限量返场] 怪诞乔克服装礼包」),去掉类目前缀再截断 */
|
||||
const giftChipLabel = (name: string): string => {
|
||||
const short = name.replace(/^\[[^\]]*\]\s*/, '').trim() || name;
|
||||
return short.length > 10 ? `${short.slice(0, 10)}…` : short;
|
||||
};
|
||||
|
||||
const renderFrequentGiftChips = (
|
||||
current: string | undefined,
|
||||
pick: (name: string) => void,
|
||||
) => {
|
||||
const choices = frequentGiftChoices();
|
||||
if (choices.length === 0) return null;
|
||||
return (
|
||||
<Space size={6} wrap style={{ marginBottom: 6 }}>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>常用礼包:</Text>
|
||||
{choices.map((item) => (
|
||||
<Tooltip key={item.name} title={`${item.name}(用过 ${item.used} 次)`}>
|
||||
<Button
|
||||
size="small"
|
||||
type={current === item.name ? 'primary' : 'default'}
|
||||
onClick={() => pick(item.name)}
|
||||
>
|
||||
{giftChipLabel(item.name)}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
// 表头排序:一次正序、再点反序(Table 上限制 sortDirections,不会出现「第三次取消」)。
|
||||
const sortProps = (key: CollabSortKey) => ({
|
||||
key,
|
||||
@@ -2069,31 +2123,20 @@ export default function HuyaCollabPage() {
|
||||
createForm.resetFields();
|
||||
const draft = readCreateDraft(user?.id);
|
||||
if (draft && hasDraftContent(draft)) {
|
||||
// 上次填了一半:原样恢复(CK / 礼包 / 截图 / 备注都在),并重新验证暂存的 CK
|
||||
const restored = { ...draft };
|
||||
const restoredGift = String(restored.gift_name ?? '').trim();
|
||||
if (
|
||||
restoredGift
|
||||
&& giftOptions.length > 0
|
||||
&& !giftOptions.some((gift) => gift.name === restoredGift)
|
||||
) {
|
||||
restored.gift_name = '';
|
||||
setGiftHint(`草稿里的「${restoredGift}」不在当前礼包缓存里,已清空,请重新点选`);
|
||||
} else {
|
||||
setGiftHint('');
|
||||
}
|
||||
createForm.setFieldsValue({ ...restored });
|
||||
// 上次填了一半:订单号 / 店铺 / CK / 截图 / 备注都原样恢复,并重新验证暂存的 CK。
|
||||
// **礼包名一律留空**(2026-10-18 用户要求):礼包默认空白,不再带上次选的那个;
|
||||
// 反正上面有「常用礼包」备选,点一下就有,不值得为它记住上一次的选择。
|
||||
createForm.setFieldsValue({ ...draft, gift_name: '' });
|
||||
setGiftHint('');
|
||||
setDraftRestoredAt(draft.saved_at || Date.now());
|
||||
setCreateOpen(true);
|
||||
if (draft.ck_text.trim()) scheduleCkPreview(draft.ck_text, true);
|
||||
return;
|
||||
}
|
||||
setDraftRestoredAt(null);
|
||||
// 记住最近选的礼包:只在当前缓存里还有它时才自动带上(礼包名不接受手输)
|
||||
const lastGift = window.localStorage.getItem(LAST_GIFT_KEY);
|
||||
if (lastGift && giftOptions.some((gift) => gift.name === lastGift)) {
|
||||
createForm.setFieldsValue({ gift_name: lastGift });
|
||||
}
|
||||
// 礼包名**不预填**(2026-10-18 用户要求):以前会自动带上"上次选的",
|
||||
// 每开一单都顶着上一次的礼包,容易在没注意时建错单。
|
||||
// 想少点两下就用上面的「常用礼包」快捷按钮,点了才算选了。
|
||||
setGiftHint('');
|
||||
setCreateOpen(true);
|
||||
}}
|
||||
@@ -2587,10 +2630,14 @@ export default function HuyaCollabPage() {
|
||||
)}
|
||||
<Row gutter={16}>
|
||||
<Col span={14}>
|
||||
{renderFrequentGiftChips(createGiftValue, (name) => {
|
||||
createForm.setFieldsValue({ gift_name: name });
|
||||
setGiftHint('');
|
||||
})}
|
||||
<Form.Item
|
||||
name="gift_name"
|
||||
label="礼包名(用户购买的物品,可稍后补)"
|
||||
tooltip="只接受礼包缓存里的点选结果,可输入关键字搜索。先贴有效 CK 拉一次礼包;不选也能先建单,之后点「补资料」再选。"
|
||||
tooltip="默认空白,不会自动带上次选的礼包(2026-10-18)。只接受礼包缓存里的点选结果,可输入关键字搜索;不选也能先建单,之后点「补资料」再选。"
|
||||
extra={giftHint || (giftsCachedAt && giftOptions.length > 0
|
||||
? `礼包列表缓存于 ${giftCacheLabel}(${giftOptions.length} 个)`
|
||||
: undefined)}
|
||||
@@ -2604,10 +2651,9 @@ export default function HuyaCollabPage() {
|
||||
options={giftSelectOptions(createGiftValue)}
|
||||
disabled={giftOptions.length === 0 && !createGiftValue}
|
||||
notFoundContent={giftOptions.length === 0 ? '先在左侧贴一份有效 CK 拉取礼包列表' : '没有匹配的礼包'}
|
||||
onChange={(value: string) => {
|
||||
// 记住最近选的礼包:连开几单同一个礼包就不用反复点
|
||||
onChange={() => {
|
||||
// 选了就清掉「上次那个礼包不在本次列表里」的提示
|
||||
setGiftHint('');
|
||||
if (value) window.localStorage.setItem(LAST_GIFT_KEY, value);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -2709,6 +2755,10 @@ export default function HuyaCollabPage() {
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
{renderFrequentGiftChips(
|
||||
supplementGiftValue ?? supplementTarget.gift_name,
|
||||
(name) => supplementForm.setFieldsValue({ gift_name: name }),
|
||||
)}
|
||||
<Form.Item name="gift_name" label="礼包名"
|
||||
tooltip="只接受礼包缓存里的点选结果,可输入关键字搜索;不接受手工输入">
|
||||
<Select
|
||||
|
||||
Reference in New Issue
Block a user