feat(oidc): 统一认证身份关联接口改为仅本人可操作

- 移除身份关联接口的权限标识校验
- 增加当前用户校验,拒绝操作他人的身份关联
- 扩展脚本清理管理员代绑权限项
This commit is contained in:
Ray.Hao committed 2026-10-28 08:25:41 +08:00
1 parent 49b27b26b5
commit e77d0b1f4f
191 files changed
+5898 -3271

No files matched your search

+34 -42
View File
@@ -1,10 +1,7 @@
# 动态表单模块(可选扩展)
# Copyright (c) 2026-present, youlai.tech
-- 动态表单模块扩展:建表、菜单与示例数据,可重复执行
-- 需先执行 ../youlai-admin.sql
-- Copyright (c) 2026-present, youlai.tech
-- ----------------------------------------------------------------------------
-- 动态表单模块扩展脚本(全量执行,可重复运行)
-- 前置:请先执行 ../youlai-admin.sql(本脚本向 sys_menu/sys_role_menu 插入数据)
-- ----------------------------------------------------------------------------
USE youlai_admin;
SET NAMES utf8mb4;
@@ -57,9 +54,8 @@ CREATE TABLE `form_data` (
-- ----------------------------
-- 表结构:form_snapshot
-- ----------------------------
-- 版本快照表:发布时固化规则,数据回显按提交时版本加载,
-- 防止表单定义变更(字段删除/改名)导致历史数据回显漂移;
-- 快照只增不改,update_time 仅因实体继承 BaseEntity 保留列,无业务语义
-- 发布时固化规则,回显按提交时的版本加载,定义变更不影响历史数据
-- 只增不改;update_time 由实体继承 BaseEntity 带入,无业务语义
DROP TABLE IF EXISTS `form_snapshot`;
CREATE TABLE `form_snapshot` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
@@ -75,52 +71,48 @@ CREATE TABLE `form_snapshot` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='表单版本快照表';
-- ----------------------------
-- 菜单(扩展段顶级 ID=8,基础段 1-7 见 youlai-admin.sql)
-- 顶级目录 route_path 为 /dynamic-form,子菜单 component 指向 views/dynamic-form 下的视图且 route_path 只填当前段
-- 菜单(顶级 ID=90;子菜单 route_path 只填当前段,component 指向 views/dynamic-form 下的视图)
-- 顶级菜单 params 中的 badge 是侧边栏角标
-- ----------------------------
-- params 携 {"badge":"NEW"}:挂顶级"动态表单"一级可见(二级折叠态角标不可见),宣传期过后清空 params 即消失
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (8, 0, '0', '动态表单', 'C', '', '/dynamic-form', 'Layout', NULL, NULL, 1, 8, 'el-icon-Document', '/dynamic-form/definition', now(), now(), '{\"badge\":\"NEW\"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (801, 8, '0,8', '表单列表', 'M', 'FormDefinition', 'definition', 'dynamic-form/index', NULL, 1, 1, 1, 'el-icon-List', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80101, 801, '0,8,801', '表单查询', 'B', NULL, '', NULL, 'form:definition:list', NULL, 1, 1, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80102, 801, '0,8,801', '表单新增', 'B', NULL, '', NULL, 'form:definition:create', NULL, 1, 2, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80103, 801, '0,8,801', '表单修改', 'B', NULL, '', NULL, 'form:definition:update', NULL, 1, 3, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80104, 801, '0,8,801', '表单删除', 'B', NULL, '', NULL, 'form:definition:delete', NULL, 1, 4, '', NULL, now(), now(), NULL);
-- 表单设计器(隐藏菜单,visible=0,列表"设计"按钮携 id 跳转)
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (803, 8, '0,8', '表单设计器', 'M', 'FormDesigner', 'designer', 'dynamic-form/designer', NULL, 1, 0, 3, '', NULL, now(), now(), NULL);
-- 表单预览(隐藏菜单,visible=0,设计器"预览"按钮携 id 跳转,运行态真预览)
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (804, 8, '0,8', '表单预览', 'M', 'FormPreview', 'preview', 'dynamic-form/preview', NULL, 1, 0, 4, '', NULL, now(), now(), NULL);
-- 表单数据(隐藏菜单,visible=0,列表"数据"按钮携 formKey 跳转)
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (802, 8, '0,8', '表单数据', 'M', 'FormData', 'data', 'dynamic-form/data', NULL, 1, 0, 2, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80201, 802, '0,8,802', '数据查询', 'B', NULL, '', NULL, 'form:data:list', NULL, 1, 1, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80202, 802, '0,8,802', '数据删除', 'B', NULL, '', NULL, 'form:data:delete', NULL, 1, 2, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (90, 0, '0', '动态表单', 'C', '', '/dynamic-form', 'Layout', NULL, NULL, 1, 8, 'el-icon-Document', '/dynamic-form/definition', now(), now(), '{\"badge\":\"NEW\"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (9001, 90, '0,90', '表单列表', 'M', 'FormDefinition', 'definition', 'dynamic-form/index', NULL, 1, 1, 1, 'el-icon-List', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900101, 9001, '0,90,9001', '表单查询', 'B', NULL, '', NULL, 'form:definition:list', NULL, 1, 1, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900102, 9001, '0,90,9001', '表单新增', 'B', NULL, '', NULL, 'form:definition:create', NULL, 1, 2, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900103, 9001, '0,90,9001', '表单修改', 'B', NULL, '', NULL, 'form:definition:update', NULL, 1, 3, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900104, 9001, '0,90,9001', '表单删除', 'B', NULL, '', NULL, 'form:definition:delete', NULL, 1, 4, '', NULL, now(), now(), NULL);
-- 表单设计器:隐藏菜单,列表「设计」按钮带 id 跳转
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (9003, 90, '0,90', '表单设计器', 'M', 'FormDesigner', 'designer', 'dynamic-form/designer', NULL, 1, 0, 3, '', NULL, now(), now(), NULL);
-- 表单预览:隐藏菜单,设计器「预览」按钮带 id 跳转
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (9004, 90, '0,90', '表单预览', 'M', 'FormPreview', 'preview', 'dynamic-form/preview', NULL, 1, 0, 4, '', NULL, now(), now(), NULL);
-- 表单数据:隐藏菜单,列表「数据」按钮带 formKey 跳转
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (9002, 90, '0,90', '表单数据', 'M', 'FormData', 'data', 'dynamic-form/data', NULL, 1, 0, 2, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900201, 9002, '0,90,9002', '数据查询', 'B', NULL, '', NULL, 'form:data:list', NULL, 1, 1, '', NULL, now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900202, 9002, '0,90,9002', '数据删除', 'B', NULL, '', NULL, 'form:data:delete', NULL, 1, 2, '', NULL, now(), now(), NULL);
-- ----------------------------
-- 示例表单入口(预置双入口:内嵌菜单 + 公开外链;与 saveFormMenu 生成的结构完全一致——
-- type=M、component=dynamic-form/render、route_path=formKey、params 携 formKey、
-- route_name 遵循 FormRender+驼峰(formKey) 全局唯一约束,防发布向导重复生成)
-- 示例表单入口,结构与 saveFormMenu 生成的菜单一致(type=M、component=dynamic-form/render、
-- route_path=formKey、params 带 formKey、route_name 为 FormRender+驼峰 formKey)
-- ----------------------------
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (805, 8, '0,8', '表单示例', 'C', '', 'sample', 'Layout', NULL, NULL, 1, 5, 'el-icon-Files', '/dynamic-form/sample/open_source_survey', now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80501, 805, '0,8,805', '开源项目问卷收集', 'M', 'FormRenderOpenSourceSurvey', 'open_source_survey', 'dynamic-form/render', NULL, NULL, 1, 1, 'el-icon-Tickets', NULL, now(), now(), '{"formKey":"open_source_survey"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80502, 805, '0,8,805', '活动报名表', 'M', 'FormRenderActivityRegistration', 'activity_registration', 'dynamic-form/render', NULL, NULL, 1, 2, 'el-icon-Calendar', NULL, now(), now(), '{"formKey":"activity_registration"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (80503, 805, '0,8,805', '意见反馈', 'M', 'FormRenderFeedback', 'feedback', 'dynamic-form/render', NULL, NULL, 1, 3, 'el-icon-ChatLineRound', NULL, now(), now(), '{"formKey":"feedback"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (9005, 90, '0,90', '表单示例', 'C', '', 'sample', 'Layout', NULL, NULL, 1, 5, 'el-icon-Files', '/dynamic-form/sample/open_source_survey', now(), now(), NULL);
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900501, 9005, '0,90,9005', '开源项目问卷收集', 'M', 'FormRenderOpenSourceSurvey', 'open_source_survey', 'dynamic-form/render', NULL, NULL, 1, 1, 'el-icon-Tickets', NULL, now(), now(), '{"formKey":"open_source_survey"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900502, 9005, '0,90,9005', '活动报名表', 'M', 'FormRenderActivityRegistration', 'activity_registration', 'dynamic-form/render', NULL, NULL, 1, 2, 'el-icon-Calendar', NULL, now(), now(), '{"formKey":"activity_registration"}');
INSERT IGNORE INTO `sys_menu` (`id`, `parent_id`, `tree_path`, `name`, `type`, `route_name`, `route_path`, `component`, `perm`, `keep_alive`, `visible`, `sort`, `icon`, `redirect`, `create_time`, `update_time`, `params`) VALUES (900503, 9005, '0,90,9005', '意见反馈', 'M', 'FormRenderFeedback', 'feedback', 'dynamic-form/render', NULL, NULL, 1, 3, 'el-icon-ChatLineRound', NULL, now(), now(), '{"formKey":"feedback"}');
-- ----------------------------
-- 系统管理员角色授权(role_id=2)
-- ----------------------------
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 8), (2, 801), (2, 80101), (2, 80102), (2, 80103), (2, 80104), (2, 802), (2, 80201), (2, 80202), (2, 803), (2, 804), (2, 805), (2, 80501), (2, 80502), (2, 80503);
INSERT IGNORE INTO `sys_role_menu` VALUES (2, 90), (2, 9001), (2, 900101), (2, 900102), (2, 900103), (2, 900104), (2, 9002), (2, 900201), (2, 900202), (2, 9003), (2, 9004), (2, 9005), (2, 900501), (2, 900502), (2, 900503);
-- ----------------------------
-- 预置示例表单(开箱即用,覆盖常用组件类型;ID 段 1001-1003,避开用户自建的自增 ID)
-- 已发布(status=1)+ 双入口预置:
-- 内嵌:菜单 80501/80502/80503(动态表单 > 表单示例),menu_id 已回填,发布向导"入口管理"可直接改挂载/角色
-- 外链:is_public=1,匿名访问 /f/{form_key}(问卷/报名/反馈天然适合对外收集)
-- 示例表单:已发布,同时挂了内嵌菜单(900501-900503)与匿名外链 /f/{form_key}
-- ID 固定 1001-1003,避开用户自建的自增段
-- ----------------------------
INSERT IGNORE INTO `form_definition` (`id`, `form_key`, `form_name`, `description`, `form_json`, `options_json`, `status`, `is_public`, `menu_id`, `version`, `create_time`, `update_time`, `create_by`, `update_by`, `is_deleted`) VALUES
(1001, 'open_source_survey', '开源项目问卷收集', '面向社区的开源项目推荐与信息收集问卷', '[{"type":"input","field":"project_name","title":"项目名称","info":"","props":{"placeholder":"如 vue3-element-admin"},"validate":[{"required":true,"message":"请输入项目名称"}]},{"type":"input","field":"repo_url","title":"项目地址","info":"","props":{"placeholder":"https://github.com/xxx/xxx"},"validate":[{"required":true,"message":"请输入项目地址"}]},{"type":"select","field":"category","title":"项目领域","info":"","props":{},"options":[{"label":"前端","value":"frontend"},{"label":"后端","value":"backend"},{"label":"移动端","value":"mobile"},{"label":"AI 与大模型","value":"ai"},{"label":"开发工具","value":"tools"},{"label":"其他","value":"other"}],"validate":[{"required":true,"message":"请选择项目领域"}]},{"type":"radio","field":"license","title":"开源协议","info":"","options":[{"label":"MIT","value":"MIT"},{"label":"Apache-2.0","value":"Apache-2.0"},{"label":"GPLv3","value":"GPLv3"},{"label":"其他","value":"other"}]},{"type":"select","field":"stars","title":"Star 数量级","info":"","props":{},"options":[{"label":"100 以内","value":"lt100"},{"label":"100 ~ 1k","value":"100to1k"},{"label":"1k ~ 10k","value":"1kto10k"},{"label":"10k 以上","value":"gt10k"}]},{"type":"textarea","field":"recommend","title":"推荐理由","info":"","props":{"placeholder":"一句话说说它解决了什么问题"},"validate":[{"required":true,"message":"请填写推荐理由"}]},{"type":"input","field":"contact","title":"联系邮箱","info":"","props":{"placeholder":"选填,便于回访"}}]', '{"labelPosition":"right","size":"default"}', 1, 1, 80501, 1, now(), now(), NULL, NULL, 0),
(1002, 'activity_registration', '活动报名表', '线下活动/聚会报名登记,含场次选择与用餐需求', '[{"type":"input","field":"name","title":"姓名","info":"","props":{},"validate":[{"required":true,"message":"请输入姓名"}]},{"type":"input","field":"phone","title":"手机号码","info":"","props":{"placeholder":"用于接收活动通知"},"validate":[{"required":true,"message":"请输入手机号码"}]},{"type":"radio","field":"gender","title":"性别","info":"","options":[{"label":"男","value":"male"},{"label":"女","value":"female"}]},{"type":"checkbox","field":"sessions","title":"参加场次","info":"","options":[{"label":"主论坛","value":"main"},{"label":"工作坊 A","value":"workshop_a"},{"label":"工作坊 B","value":"workshop_b"},{"label":"晚间交流","value":"evening"}]},{"type":"inputNumber","field":"attendees","title":"同行人数","info":"","props":{"min":0,"max":10}},{"type":"radio","field":"dinner","title":"用餐需求","info":"","options":[{"label":"正常","value":"normal"},{"label":"素食","value":"vegetarian"},{"label":"无需用餐","value":"none"}]},{"type":"textarea","field":"remark","title":"备注","info":"","props":{"placeholder":"选填"}}]', '{"labelPosition":"right","size":"default"}', 1, 1, 80502, 1, now(), now(), NULL, NULL, 0),
(1003, 'feedback', '意见反馈', '产品/系统通用意见反馈表,含满意度评分', '[{"type":"select","field":"type","title":"反馈类型","info":"","props":{},"options":[{"label":"功能建议","value":"feature"},{"label":"问题报告","value":"bug"},{"label":"体验吐槽","value":"ux"},{"label":"其他","value":"other"}],"validate":[{"required":true,"message":"请选择反馈类型"}]},{"type":"rate","field":"rating","title":"整体满意度","info":"","props":{}},{"type":"textarea","field":"content","title":"反馈内容","info":"","props":{"placeholder":"请具体描述你的建议或遇到的问题"},"validate":[{"required":true,"message":"请填写反馈内容"}]},{"type":"input","field":"contact","title":"联系方式","info":"","props":{"placeholder":"选填,便于跟进回复"}}]', '{"labelPosition":"right","size":"default"}', 1, 1, 80503, 1, now(), now(), NULL, NULL, 0);
(1001, 'open_source_survey', '开源项目问卷收集', '面向社区的开源项目推荐与信息收集问卷', '[{"type":"input","field":"project_name","title":"项目名称","info":"","props":{"placeholder":"如 vue3-element-admin"},"validate":[{"required":true,"message":"请输入项目名称"}]},{"type":"input","field":"repo_url","title":"项目地址","info":"","props":{"placeholder":"https://github.com/xxx/xxx"},"validate":[{"required":true,"message":"请输入项目地址"}]},{"type":"select","field":"category","title":"项目领域","info":"","props":{},"options":[{"label":"前端","value":"frontend"},{"label":"后端","value":"backend"},{"label":"移动端","value":"mobile"},{"label":"AI 与大模型","value":"ai"},{"label":"开发工具","value":"tools"},{"label":"其他","value":"other"}],"validate":[{"required":true,"message":"请选择项目领域"}]},{"type":"radio","field":"license","title":"开源协议","info":"","options":[{"label":"MIT","value":"MIT"},{"label":"Apache-2.0","value":"Apache-2.0"},{"label":"GPLv3","value":"GPLv3"},{"label":"其他","value":"other"}]},{"type":"select","field":"stars","title":"Star 数量级","info":"","props":{},"options":[{"label":"100 以内","value":"lt100"},{"label":"100 ~ 1k","value":"100to1k"},{"label":"1k ~ 10k","value":"1kto10k"},{"label":"10k 以上","value":"gt10k"}]},{"type":"textarea","field":"recommend","title":"推荐理由","info":"","props":{"placeholder":"一句话说说它解决了什么问题"},"validate":[{"required":true,"message":"请填写推荐理由"}]},{"type":"input","field":"contact","title":"联系邮箱","info":"","props":{"placeholder":"选填,便于回访"}}]', '{"labelPosition":"right","size":"default"}', 1, 1, 900501, 1, now(), now(), NULL, NULL, 0),
(1002, 'activity_registration', '活动报名表', '线下活动/聚会报名登记,含场次选择与用餐需求', '[{"type":"input","field":"name","title":"姓名","info":"","props":{},"validate":[{"required":true,"message":"请输入姓名"}]},{"type":"input","field":"phone","title":"手机号码","info":"","props":{"placeholder":"用于接收活动通知"},"validate":[{"required":true,"message":"请输入手机号码"}]},{"type":"radio","field":"gender","title":"性别","info":"","options":[{"label":"男","value":"male"},{"label":"女","value":"female"}]},{"type":"checkbox","field":"sessions","title":"参加场次","info":"","options":[{"label":"主论坛","value":"main"},{"label":"工作坊 A","value":"workshop_a"},{"label":"工作坊 B","value":"workshop_b"},{"label":"晚间交流","value":"evening"}]},{"type":"inputNumber","field":"attendees","title":"同行人数","info":"","props":{"min":0,"max":10}},{"type":"radio","field":"dinner","title":"用餐需求","info":"","options":[{"label":"正常","value":"normal"},{"label":"素食","value":"vegetarian"},{"label":"无需用餐","value":"none"}]},{"type":"textarea","field":"remark","title":"备注","info":"","props":{"placeholder":"选填"}}]', '{"labelPosition":"right","size":"default"}', 1, 1, 900502, 1, now(), now(), NULL, NULL, 0),
(1003, 'feedback', '意见反馈', '产品/系统通用意见反馈表,含满意度评分', '[{"type":"select","field":"type","title":"反馈类型","info":"","props":{},"options":[{"label":"功能建议","value":"feature"},{"label":"问题报告","value":"bug"},{"label":"体验吐槽","value":"ux"},{"label":"其他","value":"other"}],"validate":[{"required":true,"message":"请选择反馈类型"}]},{"type":"rate","field":"rating","title":"整体满意度","info":"","props":{}},{"type":"textarea","field":"content","title":"反馈内容","info":"","props":{"placeholder":"请具体描述你的建议或遇到的问题"},"validate":[{"required":true,"message":"请填写反馈内容"}]},{"type":"input","field":"contact","title":"联系方式","info":"","props":{"placeholder":"选填,便于跟进回复"}}]', '{"labelPosition":"right","size":"default"}', 1, 1, 900503, 1, now(), now(), NULL, NULL, 0);
-- 预置表单版本快照(已发布语义 = 固化 v1 规则,防止后续编辑定义导致历史数据回显漂移)
-- 示例表单的 v1 快照
INSERT IGNORE INTO `form_snapshot` (`id`, `form_id`, `version`, `form_json`, `options_json`, `create_time`, `update_time`, `is_deleted`) VALUES
(1001, 1001, 1, (SELECT `form_json` FROM `form_definition` WHERE `id` = 1001), (SELECT `options_json` FROM `form_definition` WHERE `id` = 1001), now(), now(), 0),
(1002, 1002, 1, (SELECT `form_json` FROM `form_definition` WHERE `id` = 1002), (SELECT `options_json` FROM `form_definition` WHERE `id` = 1002), now(), now(), 0),