日期: 2026-07-30 状态: ✅ 已实施
"我的"页面增加统一的服务角色申请入口,用户可多选申请成为规划师、营养师、管家、服务商、文章管理员、活动提供商,上传身份证和资质证书,填写联系地址,提交后台审核。
现有分散的申请页面(butler/apply.vue、nutritionist/apply.vue、vendor/apply.vue、guide/register)将被此统一入口替换。
| 角色 Key | 显示名称 | 现有后端 | 说明 |
|---|---|---|---|
planner |
规划师 | GuideApplication/Guide | 成长规划师 |
nutritionist |
营养师 | User.nutritionistStatus | — |
butler |
管家 | User.butlerStatus + ButlerProfile | — |
vendor |
服务商 | User.vendorStatus + vendorInfo | 供应商/服务商 |
article_admin |
文章管理员 | 新增 User.article_admin_status | 知识管理模块 |
activity_provider |
活动提供商 | 新增 User.activity_provider_status | — |
service_role_applicationsCREATE TABLE `service_role_applications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '申请人ID',
`roles` varchar(255) NOT NULL COMMENT '申请角色,JSON数组 e.g. ["planner","nutritionist"]',
`id_card` varchar(18) DEFAULT '' COMMENT '身份证号',
`id_card_images` text COMMENT '身份证照片,JSON数组[正面URL,反面URL]',
`certificate_images` text COMMENT '资质证书照片,JSON数组',
`province` varchar(50) DEFAULT '' COMMENT '省',
`city` varchar(50) DEFAULT '' COMMENT '市',
`district` varchar(50) DEFAULT '' COMMENT '区',
`street` varchar(50) DEFAULT '' COMMENT '街道',
`address_detail` varchar(200) DEFAULT '' COMMENT '详细地址',
`status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '0-pending, 1-approved, 2-rejected',
`reject_reason` varchar(500) DEFAULT '' COMMENT '驳回原因',
`reviewed_by` int(11) DEFAULT NULL COMMENT '审核人ID',
`reviewed_at` datetime DEFAULT NULL COMMENT '审核时间',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务角色申请表';
`article_admin_status` tinyint(4) DEFAULT NULL COMMENT '0无 1待审 2通过 3驳回',
`activity_provider_status` tinyint(4) DEFAULT NULL COMMENT '0无 1待审 2通过 3驳回',
@Data
@TableName("service_role_applications")
public class ServiceRoleApplication {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private String roles; // JSON Array
private String idCard;
private String idCardImages; // JSON Array
private String certificateImages; // JSON Array
private String province;
private String city;
private String district;
private String street;
private String addressDetail;
private Integer status; // 0=pending, 1=approved, 2=rejected
private String rejectReason;
private Long reviewedBy;
private LocalDateTime reviewedAt;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
@Data
public class ServiceRoleApplyDTO {
@NotEmpty(message = "至少选择一个角色")
private List<String> roles;
private String idCard;
private List<String> idCardImages;
private List<String> certificateImages;
private String province;
private String city;
private String district;
private String street;
private String addressDetail;
}
ServiceRoleApplicationControllerPOST /api/service-role/apply → 提交申请(含图片URL列表)
POST /api/service-role/my-apply → 查询我的申请记录
POST /api/service-role/upload-image → 上传单张图片(MultipartFile, 返回图片URL)
统一 @PostMapping,返回 Result<T>。
ServiceRoleApplicationServicepublic interface ServiceRoleApplicationService {
Result submit(Long userId, ServiceRoleApplyDTO dto);
Result getMyApplication(Long userId);
Result approve(Long id, Long reviewerId);
Result reject(Long id, String reason, Long reviewerId);
}
planner → 创建 Guide 记录
nutritionist → User.nutritionistStatus = 2 (approved)
butler → User.butlerStatus = 2 + 创建 ButlerProfile
vendor → User.vendorStatus = 2
article_admin → User.article_admin_status = 2
activity_provider → User.activity_provider_status = 2
在 pages/profile/components/ProfileMenu.vue 的「个人」分组新增菜单项(因 profile.vue 传 show-services=false 隐藏了服务分组):
<view class="menu-item" @click="goToServiceRoleApply">
<text>📋 服务角色申请</text>
<text class="arrow">›</text>
</view>
goToServiceRoleApply() {
uni.navigateTo({ url: '/pages/profile/service-role-apply' })
}
pages/profile/service-role-apply.vue页面结构:
assessment/apply.vue 的 :class="{selected:...}" 模式<AddressPicker> 四级联动 + 详细地址输入框使用 uni.chooseImage() + uni.uploadFile(),先上传到服务器获取 URL,再提交表单时传 URL 列表。
export const submitServiceRoleApply = (data) => post('/api/service-role/apply', data)
export const getMyServiceRoleApply = (data) => post('/api/service-role/my-apply', data)
export const uploadServiceRoleImage = (filePath) => ... // uni.uploadFile
在 pages.json 中 profile 子包注册:
{
"path": "pages/profile/service-role-apply",
"style": { "navigationBarTitleText": "服务角色申请" }
}
cfc-web 新增 ServiceRoleApplications.vue:
pending 申请统一入口上线后:
pages/butler/apply.vue — 标记废弃,可考虑跳转到统一入口pages/nutritionist/apply.vue — 同上pages/vendor/apply.vue — 同上pages/guide/register/index.vue — 同上