feat: 技术支持工单/企微权限/开发版本管理/消息推送等迭代

This commit is contained in:
2026-08-04 21:32:13 +08:00
parent c8ea5a3119
commit 9d96c73246
1341 changed files with 0 additions and 195605 deletions
@@ -1,143 +0,0 @@
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import type { StorePackagesResponse } from '@dukang/shared-types';
import StorePackagesForm from '../components/StorePackagesForm';
import { request } from '../lib/api';
import { toastError, toastSuccess } from '../lib/toast';
import {
emptyPackage,
normalizePackageFormItems,
validatePackageFormItems,
type PackageFormItem,
} from '../lib/storePackages';
export default function StorePackagesPage() {
const { id } = useParams();
const navigate = useNavigate();
const [items, setItems] = useState<PackageFormItem[]>([emptyPackage()]);
const [pending, setPending] = useState<StorePackagesResponse['pendingRequest']>(null);
const [loading, setLoading] = useState(true);
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState('');
useEffect(() => {
if (!id) return;
setLoading(true);
request<StorePackagesResponse>('PARTNER_H5', `/partner/stores/${id}/packages`)
.then((data) => {
const base = data.pendingRequest?.packages?.length
? data.pendingRequest.packages
: data.live?.length
? data.live
: [emptyPackage()];
setItems(base.map((p, i) => ({ ...p, price: String(p.price), sortOrder: i })));
setPending(data.pendingRequest ?? null);
})
.catch((e) => setError(e instanceof Error ? e.message : '加载失败'))
.finally(() => setLoading(false));
}, [id]);
async function submitAudit() {
if (!id) return;
const msg = validatePackageFormItems(items);
if (msg) {
toastError(msg);
return;
}
if (pending?.status === 'PENDING') {
toastError('已有套餐变更审核中,请等待总部处理');
return;
}
setSubmitting(true);
try {
const packages = normalizePackageFormItems(items).map((p) => ({
...p,
price: Number(p.price).toFixed(2),
}));
await request('PARTNER_H5', `/partner/stores/${id}/packages`, {
method: 'PUT',
body: JSON.stringify({ packages }),
});
toastSuccess('已提交审核');
navigate(`/stores/${id}`);
} catch (e) {
toastError(e instanceof Error ? e.message : '提交失败');
} finally {
setSubmitting(false);
}
}
if (loading) {
return (
<div className="partner-detail-page partner-home--flush-top">
<main style={{ padding: '24px 20px' }}>
<p className="label-md text-muted"></p>
</main>
</div>
);
}
return (
<div className="partner-page-sticky partner-home--flush-top">
<header className="partner-packages-page-header">
<button type="button" className="partner-packages-back" onClick={() => navigate(`/stores/${id}`)}>
<span className="material-symbols-outlined">arrow_back</span>
</button>
<h1 className="headline-md"></h1>
</header>
<main className="partner-packages-page-main">
{error ? <p className="partner-form-error" role="alert">{error}</p> : null}
{pending?.status === 'PENDING' ? (
<div className="partner-info-banner">
<span className="material-symbols-outlined" style={{ color: 'var(--color-heritage-red)' }}>hourglass_top</span>
<p className="body-md">C </p>
</div>
) : null}
{pending?.status === 'REJECTED' && pending.rejectReason ? (
<div className="partner-info-banner" style={{ background: 'rgba(180,35,24,0.06)', borderColor: 'rgba(180,35,24,0.15)' }}>
<span className="material-symbols-outlined" style={{ color: 'var(--color-heritage-red)' }}>error</span>
<p className="body-md">{pending.rejectReason}</p>
</div>
) : null}
<section className="partner-form-card">
<div className="partner-section-title">
<div className="partner-section-bar" />
<h2 className="headline-md"></h2>
</div>
<p className="label-md text-muted" style={{ marginBottom: 16 }}>
C
</p>
<StorePackagesForm
items={items}
onChange={setItems}
disabled={pending?.status === 'PENDING' || submitting}
embedded
/>
</section>
</main>
<footer className="partner-sticky-footer">
<button
type="button"
className="partner-btn-outline"
onClick={() => navigate(`/stores/${id}`)}
disabled={submitting}
>
</button>
<button
type="button"
className="partner-btn-primary"
disabled={submitting || pending?.status === 'PENDING'}
onClick={() => void submitAudit()}
>
{submitting ? '提交中…' : '提交审核'}
</button>
</footer>
</div>
);
}