Initial commit: 风影 OA 全栈源码(API/Web/Flutter/IM)

含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。
排除 node_modules、构建产物、安装包与 .env 密钥。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-02 10:04:03 +00:00
commit 76f266645d
507 changed files with 99891 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
import { Alert, Button, Form, Input, InputNumber, Switch, message } from 'antd';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { api } from '../api/client';
import { PageHeader } from './ResourcePage';
type Release = {
version?: string;
build?: number;
url?: string;
windowsUrl?: string;
linuxUrl?: string;
linuxDebUrl?: string;
changelog?: string;
force?: boolean;
publishedAt?: string;
};
export default function AppReleasePage() {
const [form] = Form.useForm<Release>();
const qc = useQueryClient();
const q = useQuery({
queryKey: ['app-release'],
queryFn: async () => {
const res = await api.get('/system/app-release');
const row = (res as { data?: Release }).data ?? res;
return row as Release;
},
});
const save = useMutation({
mutationFn: (v: Release) => api.patch('/system/app-release', v),
onSuccess: () => {
message.success('已登记新版本,手机端下次打开会提示升级');
qc.invalidateQueries({ queryKey: ['app-release'] });
},
});
return (
<>
<PageHeader title="手机端升级" description="登记 APK 版本后,员工打开「风影办公」会提示下载安装。build 必须大于手机里当前数字才会弹窗。" />
{q.data ? (
<Alert
type="info"
showIcon
style={{ marginBottom: 16 }}
message={`当前登记 ${q.data.version || '-'}build ${q.data.build ?? '-'}${q.data.publishedAt ? ` · ${q.data.publishedAt}` : ''}`}
/>
) : null}
<Form
form={form}
layout="vertical"
style={{ maxWidth: 520 }}
initialValues={q.data}
key={q.data?.publishedAt || 'empty'}
onFinish={(v) => save.mutate(v)}
>
<Form.Item name="version" label="版本号" rules={[{ required: true }]}>
<Input placeholder="1.1.0" />
</Form.Item>
<Form.Item name="build" label="Build" rules={[{ required: true }]} extra="整数,比上一版大即可">
<InputNumber min={1} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="url" label="Android 下载地址" rules={[{ required: true }]}>
<Input placeholder="https://oa.fysxkj.com/fengying-oa.apk" />
</Form.Item>
<Form.Item name="windowsUrl" label="Windows 下载地址">
<Input placeholder="https://oa.fysxkj.com/fengying-oa-setup.exe" />
</Form.Item>
<Form.Item name="linuxUrl" label="Linux tar.gz(备用)">
<Input placeholder="https://oa.fysxkj.com/fengying-oa-linux.tar.gz" />
</Form.Item>
<Form.Item name="linuxDebUrl" label="Linux debUbuntu/Debian/Deepin">
<Input placeholder="https://oa.fysxkj.com/fengying-oa_amd64.deb" />
</Form.Item>
<Form.Item name="changelog" label="更新说明">
<Input.TextArea rows={3} placeholder="这次改了什么" />
</Form.Item>
<Form.Item name="force" label="强制升级" valuePropName="checked">
<Switch />
</Form.Item>
<Button type="primary" htmlType="submit" loading={save.isPending}>
</Button>
</Form>
</>
);
}