Commit c1615014 authored by David Yang's avatar David Yang

feat: 部分字段改成选项,优化 ui

parent 12c2303f
...@@ -26,7 +26,7 @@ export default function LoginPage() { ...@@ -26,7 +26,7 @@ export default function LoginPage() {
const redirect = searchParams.get('redirect') || '/'; const redirect = searchParams.get('redirect') || '/';
const siteTitle = site?.title || site?.name || '项目管理系统'; const siteTitle = site?.title || site?.name || '部门任务管理';
const siteSubtitle = const siteSubtitle =
site?.subtitle || '项目下发、成员协作、甘特排期与个人日历统一协同'; site?.subtitle || '项目下发、成员协作、甘特排期与个人日历统一协同';
...@@ -141,7 +141,7 @@ export default function LoginPage() { ...@@ -141,7 +141,7 @@ export default function LoginPage() {
Sign In Sign In
</p> </p>
<h2 className="mt-3 text-3xl font-semibold text-slate-900"> <h2 className="mt-3 text-3xl font-semibold text-slate-900">
登录项目管理系统 登录部门任务管理
</h2> </h2>
<p className="mt-3 text-sm leading-6 text-slate-500"> <p className="mt-3 text-sm leading-6 text-slate-500">
参考 `streams-admin` 登录页改造,已接入验证码校验流程。 参考 `streams-admin` 登录页改造,已接入验证码校验流程。
......
...@@ -14,7 +14,7 @@ import clsx from 'clsx'; ...@@ -14,7 +14,7 @@ import clsx from 'clsx';
import { useContext, useEffect, useMemo, useState } from 'react'; import { useContext, useEffect, useMemo, useState } from 'react';
import { Link, Outlet, useLocation } from 'umi'; import { Link, Outlet, useLocation } from 'umi';
const APP_NAME = '项目管理系统'; const APP_NAME = '部门任务管理';
const menuGroups = [ const menuGroups = [
{ {
...@@ -272,9 +272,6 @@ export default function ProjectManagerLayout() { ...@@ -272,9 +272,6 @@ export default function ProjectManagerLayout() {
<h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95"> <h1 className="truncate text-sm font-semibold tracking-[0.02em] text-white/95">
{APP_NAME} {APP_NAME}
</h1> </h1>
<div className="mt-1 text-xs text-zinc-400">
项目资源管理工作台
</div>
</div> </div>
{applicationSwitcherButton} {applicationSwitcherButton}
</> </>
......
...@@ -35,12 +35,12 @@ ...@@ -35,12 +35,12 @@
关键字段: 关键字段:
- `project_name`:项目名称 - `project_name`:项目名称
- `big_category`:大类 - `big_category`:大类,选择项为部门管理、纪检工作、审计工作
- `project`:项目归属或项目分类补充字段 - `project`:项目归属或项目分类补充字段
- `project_owner`:项目负责人,直接关联系统用户,多值 - `project_owner`:项目负责人,直接关联系统用户,多值
- `project_collaborator`:项目协作人,直接关联系统用户,多值 - `project_collaborator`:项目协作人,直接关联系统用户,多值
- `task_source`:任务来源 - `task_source`:任务来源,选择项由 Subject 字段配置 `settings.options` 提供
- `task_nature`:任务性质 - `task_nature`:任务性质,选择项由 Subject 字段配置 `settings.options` 提供
- `occurrence_frequency`:发生频率 - `occurrence_frequency`:发生频率
- `planned_start_date` / `planned_end_date`:计划时间 - `planned_start_date` / `planned_end_date`:计划时间
- `actual_start_date` / `actual_finish_date`:实际时间 - `actual_start_date` / `actual_finish_date`:实际时间
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
1. 领导创建一条 `pm_project_task` 1. 领导创建一条 `pm_project_task`
2. 填写项目名称、计划开始日期、计划结束日期 2. 填写项目名称、计划开始日期、计划结束日期
3. 按需要补充大类、项目、任务来源、任务性质、发生频率 3. 按需要选择大类、任务来源、任务性质、发生频率,并补充项目
4. 按需勾选是否属于年度审计计划 `is_annual_audit_plan` 4. 按需勾选是否属于年度审计计划 `is_annual_audit_plan`
5. 选择一个或多个项目负责人 `project_owner` 5. 选择一个或多个项目负责人 `project_owner`
6. 选择一个或多个项目协作人 `project_collaborator` 6. 选择一个或多个项目协作人 `project_collaborator`
...@@ -128,28 +128,25 @@ ...@@ -128,28 +128,25 @@
- 结果状态分布柱状图 - 结果状态分布柱状图
- 进度区间分布柱状图 - 进度区间分布柱状图
- 成员负载 Top N 横向柱状图 - 成员负载 Top N 横向柱状图
- 维度概览区保留列表化统计: - “维度概览”区块当前意义不明确,资源统计看板暂不展示该模块;发生频率、大类、任务来源等维度待统计口径明确后再补充为独立图表或筛选项
- 发生频率
- 大类
- 任务来源
- 风险清单区展示: - 风险清单区展示:
- 即将到期项目 - 即将到期项目
- 超时项目清单 - 超时项目清单
- 风险清单区位于成员负载明细下方,采用独立全宽区块展示,避免作为右侧纵列造成页面左右高度失衡
- 建议补充统计维度: - 建议补充统计维度:
- 项目状态分布 - 项目状态分布
- 结果状态分布(按时间规则实时派生) - 结果状态分布(按时间规则实时派生)
- 发生频率分布
- 大类分布
- 任务来源分布
- 负责人/协作人负载分布 - 负责人/协作人负载分布
- 即将到期项目 - 即将到期项目
- 超时项目清单 - 超时项目清单
- 统计口径以 `pm_project_task.metadata` 的当前字段为准,优先展示: - 统计口径以 `pm_project_task.metadata` 的当前字段为准,优先展示:
- `project_status` - `project_status`
- `occurrence_frequency` - `completion_percent`
- `big_category` - `project_owner`
- `task_source` - `project_collaborator`
- `planned_end_date`
- `actual_finish_date`
### 5.1 甘特图 ### 5.1 甘特图
...@@ -229,6 +226,8 @@ const result = await queryUsers(0, 20, { ...@@ -229,6 +226,8 @@ const result = await queryUsers(0, 20, {
## 6.3 Excel 批量导入口径 ## 6.3 Excel 批量导入口径
- Excel 模板采用业务列头:`大类`、`项目`、`是否属于年度审计计划`、`发生频率`、`任务名称`、`任务来源`、`任务性质`、`计划启动时间`、`计划完成时间`、`时间进度`、`任务进度`、`任务状态`、`主办人`、`协办人1` - Excel 模板采用业务列头:`大类`、`项目`、`是否属于年度审计计划`、`发生频率`、`任务名称`、`任务来源`、`任务性质`、`计划启动时间`、`计划完成时间`、`时间进度`、`任务进度`、`任务状态`、`主办人`、`协办人1`
- `大类` 导入到 `metadata.big_category`,当前仅支持 `部门管理`、`纪检工作`、`审计工作`
- `任务来源` / `任务性质` 导入到 `metadata.task_source` / `metadata.task_nature`,应填写对应 Subject 字段 `settings.options` 中配置的存储值
- `任务名称` 导入到 `metadata.project_name` - `任务名称` 导入到 `metadata.project_name`
- `是否属于年度审计计划` 导入到 `metadata.is_annual_audit_plan`,支持 `是/否`、`true/false`、`1/0` - `是否属于年度审计计划` 导入到 `metadata.is_annual_audit_plan`,支持 `是/否`、`true/false`、`1/0`
- `主办人` 导入到 `metadata.project_owner`,`协办人1` 导入到 `metadata.project_collaborator`;支持填写系统用户 `display_name` 或 `username`,前端会先按 `username/display_name` 的 `$regex` 条件调用 `queryUsers` 查询,并最终保存为用户 `_id` 数组 - `主办人` 导入到 `metadata.project_owner`,`协办人1` 导入到 `metadata.project_collaborator`;支持填写系统用户 `display_name` 或 `username`,前端会先按 `username/display_name` 的 `$regex` 条件调用 `queryUsers` 查询,并最终保存为用户 `_id` 数组
......
...@@ -28,6 +28,12 @@ export const OCCURRENCE_FREQUENCY_OPTIONS = [ ...@@ -28,6 +28,12 @@ export const OCCURRENCE_FREQUENCY_OPTIONS = [
{ label: '低', value: '1' }, { label: '低', value: '1' },
]; ];
export const BIG_CATEGORY_OPTIONS = [
{ label: '部门管理', value: '部门管理' },
{ label: '纪检工作', value: '纪检工作' },
{ label: '审计工作', value: '审计工作' },
];
export const PRIORITY_OPTIONS = [ export const PRIORITY_OPTIONS = [
{ label: '高', value: 'high' }, { label: '高', value: 'high' },
{ label: '中', value: 'medium' }, { label: '中', value: 'medium' },
...@@ -331,11 +337,20 @@ function extractSubjectField(subject, fieldName) { ...@@ -331,11 +337,20 @@ function extractSubjectField(subject, fieldName) {
export async function loadProjectTaskFieldOptions() { export async function loadProjectTaskFieldOptions() {
try { try {
const subject = await loadSubject(PROJECT_TASK_SUBJECT); const subject = await loadSubject(PROJECT_TASK_SUBJECT);
const bigCategoryField = extractSubjectField(subject, 'big_category');
const taskSourceField = extractSubjectField(subject, 'task_source');
const taskNatureField = extractSubjectField(subject, 'task_nature');
const projectStatusField = extractSubjectField(subject, 'project_status'); const projectStatusField = extractSubjectField(subject, 'project_status');
const priorityField = extractSubjectField(subject, 'priority'); const priorityField = extractSubjectField(subject, 'priority');
const occurrenceFrequencyField = extractSubjectField(subject, 'occurrence_frequency'); const occurrenceFrequencyField = extractSubjectField(subject, 'occurrence_frequency');
return { return {
bigCategoryOptions:
normalizeSelectOptions(bigCategoryField?.settings?.options).length > 0
? normalizeSelectOptions(bigCategoryField?.settings?.options)
: BIG_CATEGORY_OPTIONS,
taskSourceOptions: normalizeSelectOptions(taskSourceField?.settings?.options),
taskNatureOptions: normalizeSelectOptions(taskNatureField?.settings?.options),
projectStatusOptions: projectStatusOptions:
normalizeSelectOptions(projectStatusField?.settings?.options).length > 0 normalizeSelectOptions(projectStatusField?.settings?.options).length > 0
? normalizeSelectOptions(projectStatusField?.settings?.options) ? normalizeSelectOptions(projectStatusField?.settings?.options)
...@@ -348,6 +363,9 @@ export async function loadProjectTaskFieldOptions() { ...@@ -348,6 +363,9 @@ export async function loadProjectTaskFieldOptions() {
}; };
} catch (error) { } catch (error) {
return { return {
bigCategoryOptions: BIG_CATEGORY_OPTIONS,
taskSourceOptions: [],
taskNatureOptions: [],
projectStatusOptions: PROJECT_STATUS_OPTIONS, projectStatusOptions: PROJECT_STATUS_OPTIONS,
priorityOptions: [], priorityOptions: [],
occurrenceFrequencyOptions: OCCURRENCE_FREQUENCY_OPTIONS, occurrenceFrequencyOptions: OCCURRENCE_FREQUENCY_OPTIONS,
......
...@@ -4,7 +4,6 @@ import { useContext, useEffect, useMemo, useState } from 'react'; ...@@ -4,7 +4,6 @@ import { useContext, useEffect, useMemo, useState } from 'react';
import ReactECharts from 'echarts-for-react'; import ReactECharts from 'echarts-for-react';
import { import {
formatDateLabel, formatDateLabel,
OCCURRENCE_FREQUENCY_LABEL_MAP,
PROJECT_STATUS_LABEL_MAP, PROJECT_STATUS_LABEL_MAP,
RESULT_STATUS_LABEL_MAP, RESULT_STATUS_LABEL_MAP,
} from '../projectTaskService'; } from '../projectTaskService';
...@@ -297,28 +296,6 @@ function ChartPanel({ title, description, option, hasData }) { ...@@ -297,28 +296,6 @@ function ChartPanel({ title, description, option, hasData }) {
); );
} }
function DimensionList({ items, emptyText }) {
if (items.length === 0) {
return <div className="text-sm text-zinc-400">{emptyText}</div>;
}
return (
<div className="space-y-3">
{items.map((item) => (
<div
key={item.key}
className="rounded-2xl border border-zinc-200 bg-zinc-50 px-4 py-4"
>
<div className="flex items-center justify-between gap-4">
<div className="min-w-0 text-sm font-medium text-zinc-800">{item.label}</div>
<div className="shrink-0 text-lg font-semibold text-zinc-950">{item.count}</div>
</div>
</div>
))}
</div>
);
}
export default function ResourceStatPage({ currentUsername = '' }) { export default function ResourceStatPage({ currentUsername = '' }) {
const userInfo = useContext(UserContext); const userInfo = useContext(UserContext);
const effectiveCurrentUsername = currentUsername || userInfo?.username || userInfo?._id || ''; const effectiveCurrentUsername = currentUsername || userInfo?.username || userInfo?._id || '';
...@@ -400,48 +377,6 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -400,48 +377,6 @@ export default function ResourceStatPage({ currentUsername = '' }) {
})) }))
.sort((left, right) => right.count - left.count); .sort((left, right) => right.count - left.count);
const frequencyGroups = Object.entries(
tasks.reduce((accumulator, task) => {
const key = task.occurrenceFrequency || 'unset';
accumulator[key] = (accumulator[key] || 0) + 1;
return accumulator;
}, {}),
)
.map(([key, count]) => ({
key,
label: key === 'unset' ? '未设置' : OCCURRENCE_FREQUENCY_LABEL_MAP[key] || key,
count,
}))
.sort((left, right) => right.count - left.count);
const categoryGroups = Object.entries(
tasks.reduce((accumulator, task) => {
const key = task.bigCategory || 'unset';
accumulator[key] = (accumulator[key] || 0) + 1;
return accumulator;
}, {}),
)
.map(([key, count]) => ({
key,
label: key === 'unset' ? '未设置' : key,
count,
}))
.sort((left, right) => right.count - left.count);
const taskSourceGroups = Object.entries(
tasks.reduce((accumulator, task) => {
const key = task.taskSource || 'unset';
accumulator[key] = (accumulator[key] || 0) + 1;
return accumulator;
}, {}),
)
.map(([key, count]) => ({
key,
label: key === 'unset' ? '未设置' : key,
count,
}))
.sort((left, right) => right.count - left.count);
const progressBuckets = PROGRESS_BUCKETS.map((bucket) => ({ const progressBuckets = PROGRESS_BUCKETS.map((bucket) => ({
...bucket, ...bucket,
count: tasks.filter((task) => { count: tasks.filter((task) => {
...@@ -495,9 +430,6 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -495,9 +430,6 @@ export default function ResourceStatPage({ currentUsername = '' }) {
currentUserTaskCount, currentUserTaskCount,
statusGroups, statusGroups,
resultStatusGroups, resultStatusGroups,
frequencyGroups,
categoryGroups,
taskSourceGroups,
progressBuckets, progressBuckets,
memberLoad, memberLoad,
upcoming, upcoming,
...@@ -635,7 +567,7 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -635,7 +567,7 @@ export default function ResourceStatPage({ currentUsername = '' }) {
/> />
</div> </div>
<div className="grid gap-6 xl:grid-cols-[1fr_1fr_0.9fr]"> <div className="grid gap-6 xl:grid-cols-2">
<ChartPanel <ChartPanel
title="进度区间分布" title="进度区间分布"
description="按 `completion_percent` 分桶,快速查看项目推进层级。" description="按 `completion_percent` 分桶,快速查看项目推进层级。"
...@@ -648,29 +580,8 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -648,29 +580,8 @@ export default function ResourceStatPage({ currentUsername = '' }) {
option={memberLoadOption} option={memberLoadOption}
hasData={dashboard.memberLoad.length > 0} hasData={dashboard.memberLoad.length > 0}
/> />
<SectionCard
title="维度概览"
description="保留发生频率、大类、任务来源三类核心统计维度。"
bodyClassName="space-y-5"
>
<div>
<div className="mb-3 text-sm font-medium text-zinc-500">发生频率</div>
<DimensionList items={dashboard.frequencyGroups.slice(0, 3)} emptyText="暂无发生频率统计数据" />
</div>
<div>
<div className="mb-3 text-sm font-medium text-zinc-500">大类</div>
<DimensionList items={dashboard.categoryGroups.slice(0, 3)} emptyText="暂无大类统计数据" />
</div> </div>
<div>
<div className="mb-3 text-sm font-medium text-zinc-500">任务来源</div>
<DimensionList items={dashboard.taskSourceGroups.slice(0, 3)} emptyText="暂无任务来源统计数据" />
</div>
</SectionCard>
</div>
<div className="grid gap-6 xl:grid-cols-[1.1fr_0.9fr]">
<SectionCard <SectionCard
title="成员负载明细" title="成员负载明细"
description="展示每位成员的关联项目、进行中项目和超时项目数量。" description="展示每位成员的关联项目、进行中项目和超时项目数量。"
...@@ -705,12 +616,11 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -705,12 +616,11 @@ export default function ResourceStatPage({ currentUsername = '' }) {
</div> </div>
</SectionCard> </SectionCard>
<div className="space-y-6">
<SectionCard <SectionCard
title="即将到期" title="即将到期"
description="按计划完成日期升序展示,便于提前提醒负责人。" description="按计划完成日期升序展示,便于提前提醒负责人。"
> >
<div className="space-y-3"> <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
{dashboard.upcoming.length > 0 ? ( {dashboard.upcoming.length > 0 ? (
dashboard.upcoming.map((task) => ( dashboard.upcoming.map((task) => (
<div <div
...@@ -734,7 +644,7 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -734,7 +644,7 @@ export default function ResourceStatPage({ currentUsername = '' }) {
title="超时清单" title="超时清单"
description="按超时天数倒序展示,帮助工作台聚焦风险项目。" description="按超时天数倒序展示,帮助工作台聚焦风险项目。"
> >
<div className="space-y-3"> <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
{dashboard.overdueList.length > 0 ? ( {dashboard.overdueList.length > 0 ? (
dashboard.overdueList.map((task) => ( dashboard.overdueList.map((task) => (
<div <div
...@@ -754,7 +664,5 @@ export default function ResourceStatPage({ currentUsername = '' }) { ...@@ -754,7 +664,5 @@ export default function ResourceStatPage({ currentUsername = '' }) {
</div> </div>
</SectionCard> </SectionCard>
</div> </div>
</div>
</div>
); );
} }
...@@ -89,12 +89,12 @@ type Record = { ...@@ -89,12 +89,12 @@ type Record = {
| 字段标签 | 字段别名 | 字段类型 | 是否主键 | 是否多值 | 是否必填 | | 字段标签 | 字段别名 | 字段类型 | 是否主键 | 是否多值 | 是否必填 |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 项目名称 | `project_name` | text | 否 | 否 | 是 | | 项目名称 | `project_name` | text | 否 | 否 | 是 |
| 大类 | `big_category` | text | 否 | 否 | 否 | | 大类 | `big_category` | select | 否 | 否 | 否 |
| 项目 | `project` | text | 否 | 否 | 否 | | 项目 | `project` | text | 否 | 否 | 否 |
| 项目负责人 | `project_owner` | user | 否 | 是 | 否 | | 项目负责人 | `project_owner` | user | 否 | 是 | 否 |
| 项目协作人 | `project_collaborator` | user | 否 | 是 | 否 | | 项目协作人 | `project_collaborator` | user | 否 | 是 | 否 |
| 任务来源 | `task_source` | text | 否 | 否 | 否 | | 任务来源 | `task_source` | select | 否 | 否 | 否 |
| 任务性质 | `task_nature` | text | 否 | 否 | 否 | | 任务性质 | `task_nature` | select | 否 | 否 | 否 |
| 发生频率 | `occurrence_frequency` | select | 否 | 否 | 否 | | 发生频率 | `occurrence_frequency` | select | 否 | 否 | 否 |
| 计划开始日期 | `planned_start_date` | date | 否 | 否 | 是 | | 计划开始日期 | `planned_start_date` | date | 否 | 否 | 是 |
| 计划结束日期 | `planned_end_date` | date | 否 | 否 | 是 | | 计划结束日期 | `planned_end_date` | date | 否 | 否 | 是 |
...@@ -109,7 +109,22 @@ type Record = { ...@@ -109,7 +109,22 @@ type Record = {
| 周进度记录 | `weekly_updates` | object | 否 | 否 | 否 | | 周进度记录 | `weekly_updates` | object | 否 | 否 | 否 |
| 是否属于年度审计计划 | `is_annual_audit_plan` | boolean | 否 | 否 | 否 | | 是否属于年度审计计划 | `is_annual_audit_plan` | boolean | 否 | 否 | 否 |
### 3.1.1 `project_status` 选项 ### 3.1.1 `big_category` 选项
| 显示值 | 存储值 |
| --- | --- |
| 部门管理 | `部门管理` |
| 纪检工作 | `纪检工作` |
| 审计工作 | `审计工作` |
### 3.1.2 `task_source` / `task_nature` 配置说明
- `task_source` 与 `task_nature` 为 `select` 类型
- 选项必须由 Subject 字段配置中的 `settings.options` 提供
- 前端表单只读取配置项生成下拉,不在代码中硬编码选项
- Excel 导入时应填写对应选项的存储值
### 3.1.3 `project_status` 选项
| 显示值 | 存储值 | | 显示值 | 存储值 |
| --- | --- | | --- | --- |
...@@ -119,7 +134,7 @@ type Record = { ...@@ -119,7 +134,7 @@ type Record = {
| 受阻 | `blocked` | | 受阻 | `blocked` |
| 已取消 | `cancelled` | | 已取消 | `cancelled` |
### 3.1.2 `occurrence_frequency` 选项 ### 3.1.4 `occurrence_frequency` 选项
| 显示值 | 存储值 | | 显示值 | 存储值 |
| --- | --- | | --- | --- |
...@@ -127,13 +142,13 @@ type Record = { ...@@ -127,13 +142,13 @@ type Record = {
| 中 | `2` | | 中 | `2` |
| 低 | `1` | | 低 | `1` |
### 3.1.3 `priority` 配置说明 ### 3.1.5 `priority` 配置说明
- 当前最新结构中,`priority` 为 `select` 类型 - 当前最新结构中,`priority` 为 `select` 类型
- 但字段定义内暂未提供 `settings.options` - 但字段定义内暂未提供 `settings.options`
- 前端生成表单时不得硬编码选项,需等对象配置或接口返回的 `settings.options` - 前端生成表单时不得硬编码选项,需等对象配置或接口返回的 `settings.options`
### 3.1.4 `weekly_updates` 子结构建议 ### 3.1.6 `weekly_updates` 子结构建议
`weekly_updates` 当前字段类型为 `object`。如业务上继续沿用“周进度记录集合”方案,建议对象内维护 `items` 数组,每项至少包含以下字段: `weekly_updates` 当前字段类型为 `object`。如业务上继续沿用“周进度记录集合”方案,建议对象内维护 `items` 数组,每项至少包含以下字段:
...@@ -155,12 +170,12 @@ type Record = { ...@@ -155,12 +170,12 @@ type Record = {
- 列表页或项目详情只展示最近一条摘要,不直接暴露底层 JSON - 列表页或项目详情只展示最近一条摘要,不直接暴露底层 JSON
- 若后端最终确认 `weekly_updates` 直接存数组,可再将本节从“对象内 `items` 数组”调整为“字段直接存数组” - 若后端最终确认 `weekly_updates` 直接存数组,可再将本节从“对象内 `items` 数组”调整为“字段直接存数组”
### 3.1.5 metadata 示例 ### 3.1.7 metadata 示例
```json ```json
{ {
"project_name": "某客户 2026 年专项项目", "project_name": "某客户 2026 年专项项目",
"big_category": "审计", "big_category": "审计工作",
"project": "2026 年专项项目", "project": "2026 年专项项目",
"project_owner": [ "project_owner": [
"69b12a47e92b1de77c94a9f6" "69b12a47e92b1de77c94a9f6"
......
...@@ -42,7 +42,7 @@ export default function SiteWrapper() { ...@@ -42,7 +42,7 @@ export default function SiteWrapper() {
setLoadError(error?.message || '加载站点配置失败'); setLoadError(error?.message || '加载站点配置失败');
setSiteInfo({ setSiteInfo({
name: '项目管理系统', name: '部门任务管理',
}); });
} finally { } finally {
if (!cancelled) { if (!cancelled) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment