一、超管端设计优化 - 文档管理SOP体系建立,docs目录重组 - 统一用户管理:跨租户全局视角,合并用户管理+公众用户 - 活动监管全模块重构:全部活动(统计卡片+阶段筛选+SuperDetail详情页)、报名数据/作品数据/评审进度(两层合一扁平列表)、成果发布(去Tab+统计+隐藏写操作) - 菜单精简:移除评委管理/评审规则/通知管理 - Bug修复:租户编辑丢失隐藏菜单、pageSize限制、主色统一 二、UGC绘本创作社区P0 - 数据库:10张新表(user_works/user_work_pages/work_tags等) - 子女账号独立化:Child升级为独立User,家长切换+独立登录 - 用户作品库:CRUD+发布审核,8个API - AI创作流程:提交→生成→保存到作品库,4个API - 作品广场:首页改造为推荐流,标签+搜索+排序 - 内容审核(超管端):作品审核+作品管理+标签管理 - 活动联动:WorkSelector作品选择器 - 布局改造:底部5Tab(发现/创作/活动/作品库/我的) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
311 lines
8.4 KiB
Markdown
311 lines
8.4 KiB
Markdown
# 赛事详情页面生成规范
|
||
|
||
## 概述
|
||
|
||
本规范用于快速生成赛事管理系统中的详情页面,这类页面具有统一的结构:
|
||
- 顶部导航栏(返回按钮 + 标题 + 操作按钮)
|
||
- 搜索表单
|
||
- 数据表格
|
||
|
||
## 页面结构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────┐
|
||
│ [← 返回] 页面标题 [操作按钮] │
|
||
├─────────────────────────────────────────────────┤
|
||
│ 搜索表单: [搜索条件...] [搜索] [重置] │
|
||
├─────────────────────────────────────────────────┤
|
||
│ 数据表格 │
|
||
│ ┌───┬──────┬──────┬──────┬──────┐ │
|
||
│ │序号│ 列1 │ 列2 │ 列3 │ 操作 │ │
|
||
│ ├───┼──────┼──────┼──────┼──────┤ │
|
||
│ │ 1 │ ... │ ... │ ... │ ... │ │
|
||
│ └───┴──────┴──────┴──────┴──────┘ │
|
||
└─────────────────────────────────────────────────┘
|
||
```
|
||
|
||
## 快速生成指令格式
|
||
|
||
向 Claude 提供以下格式的指令即可快速生成详情页面:
|
||
|
||
```
|
||
请生成一个详情页面:
|
||
|
||
页面名称:xxx
|
||
文件路径:xxx
|
||
数据来源:xxx API
|
||
|
||
标题:字段名(如 contestName)
|
||
操作按钮:按钮名称 -> 处理函数
|
||
|
||
搜索条件:
|
||
- 字段1(类型)
|
||
- 字段2(类型)
|
||
|
||
表格列:
|
||
- 列名1(数据字段)
|
||
- 列名2(数据字段)
|
||
- ...
|
||
|
||
排序:字段名 + 排序方式(升序/降序)
|
||
```
|
||
|
||
## 配置参数说明
|
||
|
||
### 1. 基础配置
|
||
|
||
| 参数 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| 页面名称 | 显示在标题旁 | 赛果发布详情 |
|
||
| 文件路径 | Vue 文件位置 | views/contests/results/Detail.vue |
|
||
| 数据来源 | API 模块 | resultsApi / worksApi |
|
||
| 标题字段 | 动态标题来源 | record.contestName |
|
||
| 返回路径 | 返回按钮跳转 | 上一页 / 指定路径 |
|
||
|
||
### 2. 操作按钮
|
||
|
||
| 属性 | 说明 |
|
||
|------|------|
|
||
| 名称 | 按钮显示文本 |
|
||
| 类型 | primary / default / danger |
|
||
| 处理函数 | 点击触发的方法 |
|
||
| 确认弹窗 | 是否需要二次确认 |
|
||
|
||
### 3. 搜索条件类型
|
||
|
||
| 类型 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| input | 输入框 | 作品编号、账号 |
|
||
| select | 下拉选择 | 状态筛选 |
|
||
| date | 日期选择 | 提交日期 |
|
||
| dateRange | 日期范围 | 时间区间 |
|
||
|
||
### 4. 表格列渲染类型
|
||
|
||
| 类型 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| index | 序号 | 自动计算 |
|
||
| text | 纯文本 | 直接显示字段值 |
|
||
| nested | 嵌套字段 | record.user?.nickname |
|
||
| array | 数组拼接 | teachers.map(t => t.name).join('、') |
|
||
| score | 分数格式 | 保留2位小数 |
|
||
| tag | 标签样式 | 状态标签 |
|
||
| org | 机构信息 | 学校 + 年级 + 班级 |
|
||
|
||
### 5. 排序配置
|
||
|
||
| 属性 | 说明 |
|
||
|------|------|
|
||
| 字段 | 排序依据的字段名 |
|
||
| 方式 | asc(升序)/ desc(降序)|
|
||
|
||
## 示例
|
||
|
||
### 赛果发布详情页
|
||
|
||
```
|
||
请生成一个详情页面:
|
||
|
||
页面名称:赛果发布详情
|
||
文件路径:views/contests/results/Detail.vue
|
||
数据来源:resultsApi.getResults
|
||
|
||
标题:contestName(赛事名称)
|
||
操作按钮:发布赛果 -> handlePublish(需确认)
|
||
|
||
搜索条件:
|
||
- workNo 作品编号(input)
|
||
- accountNo 报名账号(input)
|
||
|
||
表格列:
|
||
- 序号(index)
|
||
- 作品编号(workNo)
|
||
- 评委评分(finalScore,分数格式)
|
||
- 姓名(registration.user.nickname)
|
||
- 账号(registration.user.username)
|
||
- 机构信息(registration.user,机构格式)
|
||
- 指导老师(registration.teachers,数组拼接)
|
||
|
||
排序:finalScore 降序
|
||
```
|
||
|
||
### 报名记录详情页
|
||
|
||
```
|
||
请生成一个详情页面:
|
||
|
||
页面名称:报名记录
|
||
文件路径:views/contests/registrations/Records.vue
|
||
数据来源:registrationsApi.getList
|
||
|
||
标题:contestName(赛事名称)
|
||
操作按钮:无
|
||
|
||
搜索条件:
|
||
- accountNo 报名账号(input)
|
||
- registrationState 审核状态(select)
|
||
|
||
表格列:
|
||
- 序号(index)
|
||
- 报名账号(accountNo)
|
||
- 姓名(user.nickname)
|
||
- 机构信息(user,机构格式)
|
||
- 指导老师(teachers,数组拼接)
|
||
- 审核状态(registrationState,标签)
|
||
- 报名时间(registrationTime,日期)
|
||
- 操作(查看详情、审核)
|
||
|
||
排序:registrationTime 降序
|
||
```
|
||
|
||
## 页面模板代码
|
||
|
||
```vue
|
||
<template>
|
||
<div class="detail-page">
|
||
<!-- 顶部导航 -->
|
||
<div class="page-header">
|
||
<div class="header-left">
|
||
<a-button type="text" @click="handleBack">
|
||
<template #icon><ArrowLeftOutlined /></template>
|
||
返回
|
||
</a-button>
|
||
<span class="page-title">{{ pageTitle }}</span>
|
||
</div>
|
||
<div class="header-right">
|
||
<a-button type="primary" @click="handleAction">
|
||
{{ actionButtonText }}
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 搜索表单 -->
|
||
<a-form
|
||
:model="searchParams"
|
||
layout="inline"
|
||
class="search-form"
|
||
@finish="handleSearch"
|
||
>
|
||
<!-- 根据配置生成搜索项 -->
|
||
<a-form-item>
|
||
<a-button type="primary" html-type="submit">
|
||
<template #icon><SearchOutlined /></template>
|
||
搜索
|
||
</a-button>
|
||
<a-button style="margin-left: 8px" @click="handleReset">
|
||
<template #icon><ReloadOutlined /></template>
|
||
重置
|
||
</a-button>
|
||
</a-form-item>
|
||
</a-form>
|
||
|
||
<!-- 数据表格 -->
|
||
<a-table
|
||
:columns="columns"
|
||
:data-source="dataSource"
|
||
:loading="loading"
|
||
:pagination="pagination"
|
||
row-key="id"
|
||
@change="handleTableChange"
|
||
>
|
||
<template #bodyCell="{ column, record, index }">
|
||
<!-- 根据配置生成列渲染 -->
|
||
</template>
|
||
</a-table>
|
||
</div>
|
||
</template>
|
||
```
|
||
|
||
## 特殊字段渲染规范
|
||
|
||
### 机构信息(org 类型)
|
||
```vue
|
||
<template v-else-if="column.key === 'org'">
|
||
<div>
|
||
<div>{{ record.user?.tenant?.name || "-" }}</div>
|
||
<div v-if="record.user?.student?.class" class="org-detail">
|
||
{{ record.user.student.class.grade?.name }}
|
||
{{ record.user.student.class.name }}
|
||
</div>
|
||
</div>
|
||
</template>
|
||
```
|
||
|
||
### 指导老师(数组拼接)
|
||
```vue
|
||
<template v-else-if="column.key === 'teachers'">
|
||
{{ formatTeachers(record.teachers || record.registration?.teachers) }}
|
||
</template>
|
||
|
||
// 格式化函数
|
||
const formatTeachers = (teachers: any[]) => {
|
||
if (!teachers || teachers.length === 0) return "-"
|
||
return teachers.map(t => t.user?.nickname || t.user?.username).join("、")
|
||
}
|
||
```
|
||
|
||
### 分数格式
|
||
```vue
|
||
<template v-else-if="column.key === 'score'">
|
||
<span v-if="record.finalScore !== null" class="score">
|
||
{{ Number(record.finalScore).toFixed(2) }}
|
||
</span>
|
||
<span v-else>-</span>
|
||
</template>
|
||
```
|
||
|
||
## 样式规范
|
||
|
||
```css
|
||
.detail-page {
|
||
padding: 0;
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 16px;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: 16px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.search-form {
|
||
margin-bottom: 16px;
|
||
padding: 16px;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.org-detail {
|
||
font-size: 12px;
|
||
color: #666;
|
||
margin-top: 2px;
|
||
}
|
||
|
||
.score {
|
||
font-weight: bold;
|
||
color: #52c41a;
|
||
}
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. **API 数据**:确保后端返回了所需的关联数据(如 user、teachers、tenant、student.class.grade)
|
||
2. **排序字段**:需要后端支持对应字段的排序
|
||
3. **权限控制**:操作按钮需要配置权限检查
|
||
4. **空值处理**:所有字段都需要处理空值情况,显示 "-"
|
||
5. **嵌套数据**:使用可选链操作符 `?.` 避免空指针错误
|