213 行
5.5 KiB
Plaintext
213 行
5.5 KiB
Plaintext
/**
|
|
* OmniCard AI (CRMmp) - 产品相册与标杆案例移动端业务逻辑驱动层
|
|
* 严格遵循 uts 强类型契约与 AGENTS.md 规范
|
|
*/
|
|
|
|
import { CardCase, OwnerPageData, OwnerPageQuery } from '../../../common/types.uts';
|
|
import {
|
|
fetchCardCasesPage,
|
|
addCardCase,
|
|
updateCardCase,
|
|
deleteCardCase,
|
|
} from '../../../common/api.uts';
|
|
import { getCurrentLocale, getOmniText } from '../../../common/locale.uts';
|
|
|
|
export const PRESET_CASE_METRICS: string[] = [
|
|
'+320% ROI',
|
|
'+150% 留资率',
|
|
'45k+ 海外线索',
|
|
'2M+ 全球曝光',
|
|
'Top 1 细分类目',
|
|
];
|
|
|
|
export type CasesApi = {
|
|
fetchPage: (query: OwnerPageQuery) => Promise<OwnerPageData<CardCase>>;
|
|
addCase: (data: Partial<CardCase>) => Promise<CardCase>;
|
|
updateCase: (data: Partial<CardCase> & { id: string | number }) => Promise<CardCase>;
|
|
deleteCase: (id: string | number) => Promise<boolean>;
|
|
};
|
|
|
|
export const defaultCasesApi: CasesApi = {
|
|
fetchPage: (query: OwnerPageQuery) => fetchCardCasesPage(query),
|
|
addCase: (data: Partial<CardCase>) => addCardCase(data),
|
|
updateCase: (data: Partial<CardCase> & { id: string | number }) => updateCardCase(data),
|
|
deleteCase: (id: string | number) => deleteCardCase(id),
|
|
};
|
|
|
|
export type CasesState = {
|
|
cardId: string | number;
|
|
list: CardCase[];
|
|
loading: boolean;
|
|
empty: boolean;
|
|
errorMessage: string;
|
|
drawerVisible: boolean;
|
|
editingCase: Partial<CardCase> | null;
|
|
saving: boolean;
|
|
};
|
|
|
|
export function createCasesState(cardId: string | number): CasesState {
|
|
return {
|
|
cardId,
|
|
list: [],
|
|
loading: false,
|
|
empty: false,
|
|
errorMessage: '',
|
|
drawerVisible: false,
|
|
editingCase: null,
|
|
saving: false,
|
|
};
|
|
}
|
|
|
|
export function validateCaseForm(form: Partial<CardCase>): string | null {
|
|
const title = form.title != null ? form.title.trim() : '';
|
|
if (title === '') {
|
|
return '请输入案例或产品标题';
|
|
}
|
|
if (title.length > 150) {
|
|
return '标题长度不能超过 150 个字符';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export async function loadCases(
|
|
state: CasesState,
|
|
api: CasesApi = defaultCasesApi
|
|
): Promise<void> {
|
|
state.loading = true;
|
|
state.errorMessage = '';
|
|
try {
|
|
const res = await api.fetchPage({
|
|
page: 1,
|
|
size: 50,
|
|
cardId: state.cardId,
|
|
});
|
|
const items = res.list != null ? res.list : [];
|
|
state.list = items;
|
|
state.empty = items.length === 0;
|
|
} catch (err: any) {
|
|
state.errorMessage = err.message || '加载案例列表失败';
|
|
} finally {
|
|
state.loading = false;
|
|
}
|
|
}
|
|
|
|
export async function saveCase(
|
|
state: CasesState,
|
|
form: Partial<CardCase>,
|
|
api: CasesApi = defaultCasesApi
|
|
): Promise<boolean> {
|
|
const err = validateCaseForm(form);
|
|
if (err !== null) {
|
|
state.errorMessage = err;
|
|
return false;
|
|
}
|
|
|
|
state.saving = true;
|
|
state.errorMessage = '';
|
|
try {
|
|
const payload: Partial<CardCase> = {
|
|
...form,
|
|
cardId: state.cardId,
|
|
title: form.title!.trim(),
|
|
};
|
|
|
|
if (form.id != null) {
|
|
await api.updateCase({
|
|
...payload,
|
|
id: form.id,
|
|
});
|
|
} else {
|
|
await api.addCase(payload);
|
|
}
|
|
|
|
state.drawerVisible = false;
|
|
state.editingCase = null;
|
|
await loadCases(state, api);
|
|
return true;
|
|
} catch (err: any) {
|
|
state.errorMessage = err.message || '保存案例失败';
|
|
return false;
|
|
} finally {
|
|
state.saving = false;
|
|
}
|
|
}
|
|
|
|
export async function deleteCase(
|
|
state: CasesState,
|
|
id: string | number,
|
|
api: CasesApi = defaultCasesApi
|
|
): Promise<boolean> {
|
|
state.saving = true;
|
|
state.errorMessage = '';
|
|
try {
|
|
const ok = await api.deleteCase(id);
|
|
if (ok) {
|
|
await loadCases(state, api);
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (err: any) {
|
|
state.errorMessage = err.message || '删除案例失败';
|
|
return false;
|
|
} finally {
|
|
state.saving = false;
|
|
}
|
|
}
|
|
|
|
export type CasesCopyKey =
|
|
| 'title'
|
|
| 'subtitle'
|
|
| 'addBtn'
|
|
| 'editBtn'
|
|
| 'deleteBtn'
|
|
| 'emptyTitle'
|
|
| 'emptyDesc'
|
|
| 'fieldTitle'
|
|
| 'fieldClient'
|
|
| 'fieldDuration'
|
|
| 'fieldMetrics'
|
|
| 'fieldDesc'
|
|
| 'fieldCover'
|
|
| 'saveBtn'
|
|
| 'cancelBtn';
|
|
|
|
export function resolveCasesText(key: CasesCopyKey): string {
|
|
const locale = getCurrentLocale();
|
|
const zh = locale === 'zh-CN';
|
|
|
|
switch (key) {
|
|
case 'title':
|
|
return zh ? '产品相册与标杆案例' : 'Portfolio & Case Studies';
|
|
case 'subtitle':
|
|
return zh ? '随时维护产品画廊与标杆案例,在微官网中向全球买家展现硬核实力' : 'Showcase your products and case studies on your micro-site.';
|
|
case 'addBtn':
|
|
return zh ? '新增产品案例' : 'Add Case Study';
|
|
case 'editBtn':
|
|
return zh ? '编辑' : 'Edit';
|
|
case 'deleteBtn':
|
|
return zh ? '删除' : 'Delete';
|
|
case 'emptyTitle':
|
|
return zh ? '暂无产品案例' : 'No Cases Yet';
|
|
case 'emptyDesc':
|
|
return zh ? '点击下方按钮,拍照或上传您的首个产品相册与案例' : 'Tap below to add your first product showcase or case study.';
|
|
case 'fieldTitle':
|
|
return zh ? '案例/产品名称' : 'Title';
|
|
case 'fieldClient':
|
|
return zh ? '合作客商/品牌 (选填)' : 'Client / Brand';
|
|
case 'fieldDuration':
|
|
return zh ? '项目周期 (选填)' : 'Timeline';
|
|
case 'fieldMetrics':
|
|
return zh ? '量化成效标签' : 'Key Metrics Tag';
|
|
case 'fieldDesc':
|
|
return zh ? '方案成果简述' : 'Overview';
|
|
case 'fieldCover':
|
|
return zh ? '产品封面与相册图片' : 'Cover & Photos';
|
|
case 'saveBtn':
|
|
return zh ? '保存案例' : 'Save Case';
|
|
case 'cancelBtn':
|
|
return zh ? '取消' : 'Cancel';
|
|
default:
|
|
return '';
|
|
}
|
|
}
|