76f266645d
含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。 排除 node_modules、构建产物、安装包与 .env 密钥。 Co-authored-by: Cursor <cursoragent@cursor.com>
136 lines
4.5 KiB
TypeScript
136 lines
4.5 KiB
TypeScript
import { Button, Segmented, Space, Table, Tag } from 'antd';
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
|
import { api } from '../api/client';
|
|
import { PageHeader, unwrapList } from './ResourcePage';
|
|
import { ApplyBucketBar, PROCESS_BUCKETS } from './ApplyBucketBar';
|
|
import { fmtCreated } from '../time';
|
|
import { zh } from '../labels';
|
|
import { HR_APPLY_LABEL } from './hrStatus';
|
|
|
|
const SOURCE_LABEL: Record<string, string> = {
|
|
HR: '人事',
|
|
SEAL: '用章',
|
|
OFFICE: '办公',
|
|
EXPENSE: '费用',
|
|
};
|
|
|
|
const KIND_LABEL: Record<string, string> = {
|
|
...HR_APPLY_LABEL,
|
|
SEAL: '用章',
|
|
ASSET_BUY: '资产购置',
|
|
ASSET_USE: '资产领用',
|
|
VEHICLE: '用车',
|
|
EXPENSE: '报销',
|
|
LOAN: '借支',
|
|
};
|
|
|
|
const BUCKET_META: Record<string, { color: string; text: string }> = {
|
|
pending: { color: 'processing', text: '待审批' },
|
|
approved: { color: 'success', text: '已通过' },
|
|
rejected: { color: 'error', text: '已驳回' },
|
|
occupying: { color: 'blue', text: '占用中' },
|
|
out: { color: 'blue', text: '外带中' },
|
|
overdue: { color: 'error', text: '逾期未还' },
|
|
returned: { color: 'success', text: '已归还' },
|
|
};
|
|
|
|
type FlowRow = {
|
|
id: string;
|
|
source: string;
|
|
kind: string;
|
|
title: string;
|
|
status: string;
|
|
bucket: string;
|
|
createdAt: string;
|
|
path: string;
|
|
};
|
|
|
|
export default function MyFlowPage() {
|
|
const [params] = useSearchParams();
|
|
const navigate = useNavigate();
|
|
const bucket = params.get('bucket') || '';
|
|
const kind = params.get('kind') || '';
|
|
const qs = new URLSearchParams();
|
|
if (bucket) qs.set('bucket', bucket);
|
|
if (kind) qs.set('kind', kind);
|
|
const endpoint = `/office/flow${qs.toString() ? `?${qs}` : ''}`;
|
|
const q = useQuery({ queryKey: [endpoint], queryFn: () => api.get(endpoint) });
|
|
const items = unwrapList(q.data).items as unknown as FlowRow[];
|
|
|
|
const setKind = (v: string) => {
|
|
const next = new URLSearchParams();
|
|
if (bucket) next.set('bucket', bucket);
|
|
if (v) next.set('kind', v);
|
|
const s = next.toString();
|
|
navigate(s ? `/office/flow?${s}` : '/office/flow');
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<PageHeader
|
|
title="我的申请"
|
|
description="跟踪自己提交的人事、用章、办公和费用。要新开一单,从右侧进对应发起页。"
|
|
extra={
|
|
<ApplyBucketBar
|
|
basePath="/office/flow"
|
|
buckets={[
|
|
...PROCESS_BUCKETS,
|
|
{ value: 'occupying', label: '占用中' },
|
|
{ value: 'out', label: '外带中' },
|
|
{ value: 'overdue', label: '逾期未还' },
|
|
]}
|
|
extra={
|
|
<Space>
|
|
<Button onClick={() => navigate('/office/hr-apply')}>人事</Button>
|
|
<Button onClick={() => navigate('/office/seal-apply')}>用章</Button>
|
|
<Button type="primary" onClick={() => navigate('/office/apply')}>
|
|
办公
|
|
</Button>
|
|
</Space>
|
|
}
|
|
/>
|
|
}
|
|
/>
|
|
<div style={{ marginBottom: 16 }}>
|
|
<Segmented
|
|
value={kind}
|
|
onChange={(v) => setKind(String(v))}
|
|
options={[
|
|
{ label: '全部类型', value: '' },
|
|
{ label: '人事', value: 'HR' },
|
|
{ label: '用章', value: 'SEAL' },
|
|
{ label: '办公', value: 'OFFICE' },
|
|
{ label: '费用', value: 'EXPENSE' },
|
|
]}
|
|
/>
|
|
</div>
|
|
<Table
|
|
className="ops-table"
|
|
rowKey={(r) => `${r.source}-${r.id}`}
|
|
loading={q.isLoading}
|
|
dataSource={items}
|
|
pagination={{ defaultPageSize: 10, showSizeChanger: true, showTotal: (n) => `共 ${n} 条` }}
|
|
columns={[
|
|
{ title: '来源', width: 80, render: (_: unknown, r: FlowRow) => SOURCE_LABEL[r.source] || r.source },
|
|
{ title: '类型', width: 110, render: (_: unknown, r: FlowRow) => KIND_LABEL[r.kind] || r.kind },
|
|
{
|
|
title: '事项',
|
|
ellipsis: true,
|
|
render: (_: unknown, r: FlowRow) => <Link to={r.path}>{r.title}</Link>,
|
|
},
|
|
{
|
|
title: '状态',
|
|
width: 110,
|
|
render: (_: unknown, r: FlowRow) => {
|
|
const s = BUCKET_META[r.bucket] || { color: 'default', text: zh(r.status) };
|
|
return <Tag color={s.color}>{s.text}</Tag>;
|
|
},
|
|
},
|
|
{ title: '创建时间', width: 170, render: (_: unknown, r: FlowRow) => fmtCreated(r.createdAt) },
|
|
]}
|
|
/>
|
|
</>
|
|
);
|
|
}
|