Compare commits

..

228 Commits

Author SHA1 Message Date
dayou
cc7866089b Fix/pinia v2 (#453)
* fix: 锁版本

* fix: 锁版本
2024-11-29 18:34:55 +08:00
dayou
c5fc734bb1 fix: 修复c端页面报错 (#448) 2024-10-30 18:02:55 +08:00
dayou
e6645c12a8 fix: 修复依赖版本 (#445)
* fix: 修复依赖版本

* fix: nanoid version

* fix: sass锁定1.79.6的版本

* nanoid reset

* fix: modern-compiler
2024-10-28 21:22:05 +08:00
luch1994
00c3e7c263 feat: 升级docker的版本 2024-10-08 21:33:40 +08:00
Donald Yang
ea6b0d50f0 feat:自动保存优化 (#435) 2024-10-08 21:33:29 +08:00
luch
f73bf6fdeb feat: 把report迁移到src下 (#440) 2024-10-08 21:33:16 +08:00
sudoooooo
039d634e62 feat: 优化readme 2024-10-08 15:48:00 +08:00
luch
0ce78b62a0
[Feature]: 升级状态相关功能 (#438)
* fix: 解决readme的冲突

* feat: 修改补充单测 (#437)
2024-09-30 19:18:55 +08:00
sudoooooo
2bc11c6dfe
feat: Create CODE_OF_CONDUCT.md 2024-09-27 11:13:05 +08:00
sudoooooo
e4f2cdede6 fix: 优化配置内容 2024-09-24 16:42:28 +08:00
Jiangchunfu
4b8719ab9c feat: 皮肤设置2.0 (#426)
* fix: 修复windows上传文件路径反斜杠问题

* feat: 补全服务端skinConf定义

* feat: web端皮肤背景设置2.0

* feat: 删除console.log

* feat: 皮肤设置内容结果增加背景设置以及应用皮肤设置方法抽离

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
Co-authored-by: sudoooooo <zjbbabybaby@gmail.com>
2024-09-24 16:42:20 +08:00
sudoooooo
4bc8fbc557 fix: 优化类型校验 2024-09-24 12:14:06 +08:00
sudoooooo
206f91d766 fix: 修改api 2024-09-23 15:20:29 +08:00
sudoooooo
8bece51a20 fix: 修复投票题问题 2024-09-23 14:22:35 +08:00
dayou
0ea1d81ad3 fix: 修复最少最多选择 (#412)
* fix: 修复最少最多选择

* fix: 优化获取协作下拉框在协作弹窗出现时调用

* fix: 回退最多最少选择

* perl: 代码优化以及fix lint

---------

Co-authored-by: sudoooooo <zjbbabybaby@gmail.com>
2024-09-23 14:07:22 +08:00
Jiangchunfu
602f8f4b73 fix: 修复做题页面提交reload页面 (#419)
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
Co-authored-by: sudoooooo <zjbbabybaby@gmail.com>
2024-09-23 14:07:12 +08:00
sudoooooo
930976f67e fix: 优化schema初始化管理 2024-09-23 14:07:02 +08:00
sudoooooo
e6b4c02e34 fix: 优化代码内容 2024-09-23 14:06:41 +08:00
luch
8f65b1390b feat: 修改导出和登录状态检测代码CR问题 (#431) 2024-09-23 14:06:36 +08:00
sudoooooo
c6239b2770 fix: 修复写法问题、C端组件问题 2024-09-23 14:06:19 +08:00
dayou
bf5db3f47b fix: 断点续答and编辑检测代码cr优化 (#428)
* fix: 优化代码以及去掉无用字段

* fix: 断点续答验收问题优化

* fix: 优化字段

* fix: lint

* fix: 编辑检测相关问题优化

* fix: lint

* fix: 第二批cr优化

* fix: 去掉无用代码

* fix: 调整session守卫位置

* fix: 文件大小写
2024-09-23 14:05:39 +08:00
sudoooooo
628872f27c fix: 移除有问题的功能 2024-09-23 14:05:31 +08:00
dayou
dfea4b4779 【Feature】:北大实践课作业 (#424)
* 【北大开源实践】增加数据导出功能 (#294)

* feat:添加了一个文件数据导出的功能和相应前端页面

* fix lint

* fix conflict

---------

Co-authored-by: dayou <853094838@qq.com>

* fix: components.d.ts文件ignore

* feat: Update README_EN.md

* feat: Update README.md

* feat:新增预览功能 (#257)

* feat:问卷预览功能
* feat:修复样式问题

* fix: 优化预览展示

* refactor: 重构vue3组合式API写法 (#265)

* feat: 抽离题型枚举 (#272)

* feat: 抽离题型枚举

* fix: 投放的链接加时间戳去掉ifream缓存

* feat: serve端的node engines

* feat: 权限接口请求优化以及修复其他问题 (#290)

* feat: c端路由改造 (#296)

* 【北大开源实践】增加数据导出功能 (#294)

* feat:添加了一个文件数据导出的功能和相应前端页面

* fix lint

* fix conflict

---------

Co-authored-by: dayou <853094838@qq.com>

* fix: 删除components.d.ts文件

* 【北大开源实践】- 问卷断点续答 - 前端 (#282)

* feat:增加断点续答功能

* feat:增加断点续答功能

* fix: 同步代码并且解决冲突

---------

Co-authored-by: dayou <853094838@qq.com>

* fix: 删除components.d.ts文件最终

* 【北大开源实践】-选项限制 (#284)

* format: 代码格式化 (#160)

* feat: 选项限制

* fix: 同步代码并解决冲突

* fix conflict

* fix conflict

* fix lint

* fix server lint

---------

Co-authored-by: dayou <853094838@qq.com>
Co-authored-by: XiaoYuan <2521510174@qq.com>

* feat: 登录失效检测 & 协作冲突检测 (#287)

Co-authored-by: Liuxinyi <liuxy0406@163.com>
Co-authored-by: dayou <853094838@qq.com>

* fix: peking分支同步develop并解决冲突

* fix: 修正颜色不统一 (#338)

* fix: 修正颜色不统一

* fix: 删除server下的lock文件

* 编辑冲突检测 (#351)

* perl: 选项配额优化

* fix: pinia改写

* feat: 完善北大课程相关的内容

* fix: 修复断点续答以及样式问题 (#420)

* feat: 修改readme

* [Feature]: 密码复杂度检测 (#407)

* feat: 密码复杂度检测

* chore: 改为服务端校验

* feat: 优化展示

* fix:修复编辑页在不同element版本下表现不一致问题 (#406)

* fix: 通过声明element最低版本来确定tab样式表现

* fix lint

* feat(选项设置扩展):选择类题型增加选项排列配置 (#403)

* build: add optimizeDeps packages

* feat(选项设置扩展):选择类题型增加选项排列配置

* feat(选项设置扩展): 验收问题修复

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>

* fix: 删除多余内容

* feat: 优化登录窗口

* fix: 修复断点续答以及样式问题

fix: 修复选项引用验收bug

fix: 修复断点续答问题

fix: 修复断点续答

fix: ignore

fix: 修复投票题默认值

fix: 优化断点续答逻辑

fix: 选中图标适应高度

fix: 回退最大最小选择

fix: 修复断点续答

fix: 修复elswitch不更新问题

fix: 修复访问密码更新不生效问题

fix: 修复样式

fix: 修复多选题最大最小限制

fix: 优化断点续答问题

修复多选题命中最多选择后无法取消问题

fix: 修复服务端的富文本解析

fix:  lint

fix: min error

fix: 修复最少最多选择

fix: 修复投票问卷的最少最多选择

fix: 兼容断点续答情况下选项配额为0的情况

fix: 兼容断点续答情况下选项配额为0的情况

fix: 兼容单选题的断点续答下的选项配额

fix: 修复添加选项问题

fix: 前端提示服务的配额已满

fix: 更新填写的过程中配额减少情况

---------

Co-authored-by: sudoooooo <zjbbabybaby@gmail.com>
Co-authored-by: Stahsf <30379566+50431040@users.noreply.github.com>
Co-authored-by: Jiangchunfu <mrj_kevin@163.com>
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>

* feat: 修改验收问题 (#421)

* fix lint

---------

Co-authored-by: Oseast <162945153+Oseast@users.noreply.github.com>
Co-authored-by: sudoooooo <zjbbabybaby@gmail.com>
Co-authored-by: chaorenluo <1243357953@qq.com>
Co-authored-by: Realabiha <48506355+Realabiha@users.noreply.github.com>
Co-authored-by: shiyiting763 <70299297+shiyiting763@users.noreply.github.com>
Co-authored-by: yiyeah <68832436+yiyeah@users.noreply.github.com>
Co-authored-by: XiaoYuan <2521510174@qq.com>
Co-authored-by: Xinyi Liu <74805961+colmon46@users.noreply.github.com>
Co-authored-by: Liuxinyi <liuxy0406@163.com>
Co-authored-by: nil <wangweiguo2013@icloud.com>
Co-authored-by: 王晓聪 <wang86976110@126.com>
Co-authored-by: taoshuang <taoshuang@didiglobal.com>
Co-authored-by: luch1994 <1097650398@qq.com>
Co-authored-by: Stahsf <30379566+50431040@users.noreply.github.com>
Co-authored-by: Jiangchunfu <mrj_kevin@163.com>
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
Co-authored-by: luch <32321690+luch1994@users.noreply.github.com>
2024-09-23 14:05:02 +08:00
Jiangchunfu
afbd63646a fix: 修复富文本编辑器上传图片 (#410)
* fix: 修复题目标题插入图片异常问题

* fix: 修改事件监听顺序,避免编辑图片百分比时重新渲染工具条而找不到点击的dom

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-09-23 14:03:59 +08:00
Stahsf
39c80352b3 test: 密码检测用例 (#411)
* feat: 密码复杂度检测

* chore: 改为服务端校验

* test: 修改用例

* test: 添加getPasswordStrength测试用例
2024-09-23 14:03:54 +08:00
sudoooooo
16b02fcbaa feat: 优化登录窗口 2024-09-23 14:03:47 +08:00
sudoooooo
e197aa41fe fix: 删除多余内容 2024-09-23 14:03:40 +08:00
Jiangchunfu
2d6bba2224 feat(选项设置扩展):选择类题型增加选项排列配置 (#403)
* build: add optimizeDeps packages

* feat(选项设置扩展):选择类题型增加选项排列配置

* feat(选项设置扩展): 验收问题修复

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-09-23 14:02:38 +08:00
dayou
5c6a45875c fix:修复编辑页在不同element版本下表现不一致问题 (#406)
* fix: 通过声明element最低版本来确定tab样式表现

* fix lint
2024-09-23 14:02:27 +08:00
sudoooooo
f5c2bd88f2 feat: 优化展示 2024-09-23 14:02:18 +08:00
Stahsf
1c6908b6a5 [Feature]: 密码复杂度检测 (#407)
* feat: 密码复杂度检测

* chore: 改为服务端校验
2024-09-23 14:01:43 +08:00
sudoooooo
99739064cc feat: 修改readme 2024-08-30 12:01:57 +08:00
sudoooooo
dc82ee9be6 feat: 优化换行 2024-08-14 21:32:42 +08:00
dayou
7b710d4d13 fix: 删除分页判断是否存在题目的逻辑关联 (#402) 2024-08-14 21:32:32 +08:00
Liang-Yaxin
2ecbc53983 fix: 问卷列表更多按钮图标优化 (#401) 2024-08-14 21:16:23 +08:00
dayou
c3f8b2a938 feat: 跳转逻辑稳定版 (#399)
* feat: 跳转逻辑 (#388)

* fix: 跳转逻辑优化 (#397)

* fix: 跳转逻辑优化

* fix: processJumpSkip逻辑放在题目组件中
2024-08-14 18:06:49 +08:00
sudoooooo
e7adb05c3d fix: 修复高级设置迁移后无法交互问题 2024-08-14 18:06:38 +08:00
dayou
5e30c2898e fix: 更新iconfont链接 (#398) 2024-08-14 18:06:27 +08:00
sudoooooo
7e83c926ae feat: 高级设置组件迁移 2024-08-14 18:05:38 +08:00
sudoooooo
26f8526f70 feat: 升级iconfont 2024-08-13 11:47:20 +08:00
sudoooooo
b5bce230c1 fix: 新建问卷重置计数 2024-08-12 23:16:11 +08:00
Jiangchunfu
624308bae8 feat: 整卷增加基础配置:必填、显示类型、显示序号、显示分割线 (#391)
* feat: 增加整卷配置功能

* fix: 限制单题修改配置时只对基础配置进行更新全局基础配置操作

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-08-12 23:16:05 +08:00
Jiangchunfu
28591f00a3 feat: C端增加重新填写入口, #182 (#392)
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-08-12 23:15:53 +08:00
sudoooooo
23f4dd5756 feat: 优化readme 2024-08-12 19:42:21 +08:00
sudoooooo
9392b93d10 fix: 连续添加题目频繁触发事件导致页面卡顿 2024-08-12 16:09:40 +08:00
sudoooooo
da08621dc6 feat: action不处理format 2024-08-12 14:10:08 +08:00
Jiangchunfu
3ba41f78ad refactor: 题目删除和逻辑关联优化,#182 (#393)
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-08-12 14:10:03 +08:00
sudoooooo
c8c1031c29 fix: 皮肤设置tab问题 2024-08-07 22:10:35 +08:00
sudoooooo
0b6d48bddc fix: 修复白名单切换和空间成员名字问题 2024-08-07 22:10:32 +08:00
Jiangchunfu
4e993f4d55 refactor: 设置器加载统一,代码优化 #269 (#383)
* feat: 小功能建设(4)

* refactor: 设置器加载统一,代码优化 #269

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-08-07 14:56:15 +08:00
sudoooooo
12206fd3ee feat: 修改Readme 2024-08-06 23:46:39 +08:00
sudoooooo
3cc76d0b61 feat: 修改字段 2024-08-06 19:59:52 +08:00
sudoooooo
4a158ae6e8 feat: 优化分页器结构 2024-08-06 19:33:31 +08:00
chaorenluo
c330e6000d feat:新增分页功能 (#382)
* feat:新增分页功能

* 修复type-check检查

* fix: server  type-check

* fix:修改服务端测试用例

* fix:修复分页bug
2024-08-06 18:08:36 +08:00
Jiangchunfu
d9e9770eb8 feat: 小功能建设(4) (#379) 2024-08-04 12:41:24 +08:00
Jiangchunfu
0745d90a5c
fix: 修复题目未聚焦时拖拽按钮失效问题 (#375)
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-08-04 12:38:59 +08:00
sudoooooo
e58be83214 fix: 修复字段difTime->diffTime 2024-08-04 12:21:37 +08:00
Jiangchunfu
9dbe7cfa2b 小功能优化8 (#371)
* refactor: 去除重复元素

* feat: edit 布局优化

* style: 题目大纲滚动时固定tab-header

---------

Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-07-31 20:32:26 +08:00
离谱
15d93abea3 fix(Navbar):修复了短标题hover空白处会触发指示框的bug (#365)
fix(Navbar):修复了短标题hover空白处会触发指示框的bug
2024-07-30 15:41:27 +08:00
dayou
9ca27118c4 fix: 修复提交设置 (#370) 2024-07-30 15:41:20 +08:00
sudoooooo
29b37b7ed0 fix: 修复白名单密码问题 2024-07-23 22:50:50 +08:00
sudoooooo
d36e33e4df feat: 优化结构 2024-07-23 22:22:27 +08:00
sudoooooo
4ac07ef938 feat: 优化编辑页模块和配置结构 2024-07-23 22:07:46 +08:00
Stahsf
ee9a1ea9c7 feat: 白名单功能-服务端 (#357) 2024-07-23 22:01:37 +08:00
chaorenluo
df6e14c585 feat: 前端新增白名单功能 2024-07-23 22:01:26 +08:00
sudoooooo
0b53b78cda Merge branch 'feature/pinia' 2024-07-23 21:27:04 +08:00
dayou
6c396c6ec8 fix: 修复设置器不更新问题 (#361) 2024-07-23 15:40:44 +08:00
Jiangchunfu
591a98bff1
fix: 修复新增同类型题目设置值不变问题 (#359)
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-07-23 14:17:31 +08:00
sudoooooo
41d072bc90 feat: 优化图片尺寸用于移动端 2024-07-18 21:08:59 +08:00
nil
358e822660 feat: 题目与选项支持图片 (#291)
* feat: 题目与选项支持图片

* fix: 修复使用本地存储时文件访问路径不正确的问题

* fix: 图片编辑表单无法输入

* chore: 添加上传文件夹到gitignore

* fix: 两个#app的问题
2024-07-18 21:08:50 +08:00
sudoooooo
3388a15462 feat: 更新readme和docker tag 2024-07-17 23:12:40 +08:00
sudoooooo
ea5f99b0d2 fix: format报错 2024-07-16 11:33:41 +08:00
Jiangchunfu
c0387b1521 feat: 题型硬编码优化 (#343)
Co-authored-by: jiangchunfu <jiangchunfu@kaike.la>
2024-07-16 11:33:35 +08:00
sudoooooo
1eabbf5df2 feat: 代码format、升级ts和lint 2024-07-15 22:40:19 +08:00
Ken
7c336e2320 feat: 空间列表分页和搜索及数据列表优化 (#344)
1、fix: 修复因滚动条宽度影响皮肤标签的问题
2、feat: 空间列表分页和搜索及数据列表样式优化
3、feat: 对部分代码进行了优化
2024-07-15 22:40:13 +08:00
sudoooooo
2044da4be9 fix: 移除选项默认选中 2024-07-15 22:40:05 +08:00
Jiangchunfu
a14d444960 feat: 功能18优化 (#342)
题目标题编辑自动focus
2024-07-15 22:39:53 +08:00
sudoooooo
5e85e5a3b9 fix: 空间列表高度 2024-07-15 22:39:45 +08:00
ysansan
99a1eeb356 问卷编辑页面题型选择tab、团队空间列表按钮优化 (#337)
* feat:问卷编辑页面题型选择tab优化

* feat: 团队空间列表按钮优化
2024-07-15 22:39:05 +08:00
sudoooooo
e42625f1aa fix: 避免element-plus提示sass语法 2024-07-15 11:21:56 +08:00
sudoooooo
b26d7b08c6 feat: 增加csdn和x 2024-07-12 16:50:26 +08:00
sudoooooo
f82de45a03 feat: 优化协作管理路径 2024-07-10 18:37:42 +08:00
Ken
e8e2a9ab2c feat: 协作者管理优化和皮肤标签样式调整 (#333)
* feat: 皮肤设置内主题分类标签样式调整

* feat: 协作者管理优化
2024-07-10 18:37:36 +08:00
Jiangchunfu
b2c3d2c0c3 feat(小功能建设): 15团队空间问卷列表页优化 (#334) 2024-07-10 17:09:43 +08:00
sudoooooo
d8adb4596c fix: sass1.77.7规则升级warning 2024-07-10 17:09:37 +08:00
hiStephen
e757da19eb feat: echarts按需引入 (#332) 2024-07-10 17:09:30 +08:00
sudoooooo
d7c772e748 fix: 修复预览页logo展示问题 2024-07-09 15:24:03 +08:00
Jiangchunfu
9fbbb87fa8 小功能优化 (#329)
* feat(换肤设置优化): 边距的颜色优化成背景色一致

* feat: 问卷设置优化
2024-07-09 15:23:56 +08:00
Ken
63e7de4fad feat: 移动端预览优化 (#326)
* feat: 移动端预览优化

* feat: C端底部logo优化
2024-07-09 12:13:40 +08:00
sudoooooo
ce3508f8be fix: 修复nginx启动render页空白问题 2024-07-08 21:07:15 +08:00
sudoooooo
2ab95463c5 fix: 优化依赖项 2024-07-01 15:35:10 +08:00
若川
dc91b69bf5 fix: 🐛 修复引入 import lodash cloneDeep debounce 错误 改为 lodash-es 了 (#322) 2024-07-01 15:35:01 +08:00
sudoooooo
83dc99e1a8 fix: fix warning 2024-06-28 17:42:18 +08:00
dayou
335765e3ea feat: 物料脱离store依赖 (#312) 2024-06-28 17:42:05 +08:00
dayou
d50f974c3d no message 2024-06-28 17:41:50 +08:00
sudoooooo
4d71238084 fix: 修复文档内容 2024-06-24 17:50:17 +08:00
sudoooooo
a7fa577837 fix: 修复预览兼容 2024-06-24 16:14:05 +08:00
sudoooooo
f7e5995add feat: 调整文档内容 2024-06-24 10:50:01 +08:00
yelang
a679ad20bb [refactor]: check for the ispc-html class is done using a regular expression to ensure that the class is only added once when the browser window is resized (#301) 2024-06-21 21:00:37 +08:00
hiStephen
2ab96606aa feat: 分题统计前端开发 (#276) 2024-06-21 16:37:11 +08:00
luch
0b42899347 feat: 新增分题统计相关功能 (#275) 2024-06-21 16:37:05 +08:00
dayou
053d9751c3 feat: c端路由改造 (#296) 2024-06-14 19:21:16 +08:00
dayou
32b1c4888d feat: 权限接口请求优化以及修复其他问题 (#290) 2024-06-14 19:07:14 +08:00
dayou
c122589a2e feat: 抽离题型枚举 (#272)
* feat: 抽离题型枚举

* fix: 投放的链接加时间戳去掉ifream缓存

* feat: serve端的node engines
2024-06-14 19:07:06 +08:00
Realabiha
6559154bca refactor: 重构vue3组合式API写法 (#265) 2024-06-11 20:10:46 +08:00
sudoooooo
827497114d fix: 优化预览展示 2024-06-11 20:10:39 +08:00
chaorenluo
48fdb3138a feat:新增预览功能 (#257)
* feat:问卷预览功能
* feat:修复样式问题
2024-06-11 20:10:32 +08:00
alwayrun
cffe037269 refactor: 重构 management/pages/edit 目录下组件, 使用 Vue3 组合式 API 写法 (#251) 2024-06-05 17:30:31 +08:00
sudoooooo
d9255db8a9 feat: Update README.md 2024-06-05 11:46:24 +08:00
sudoooooo
89b249274f feat: Update README_EN.md 2024-06-05 11:46:19 +08:00
sudoooooo
e0da70838a feat: 优化空间展示和文案 2024-06-04 18:05:30 +08:00
sudoooooo
c70a93e54e fix: 修复defineProps无需import的warning 2024-06-04 16:26:33 +08:00
sudoooooo
be9da7811d feat: 优化初始化请求 2024-06-04 16:18:26 +08:00
Jiang Yu
8a4cad1195 Update HistoryPanel.vue (#256)
1、点击“修改历史”:请求修改历史列表;点击“发布历史”:请求发布历史列表。
2、接口请求过程中增加loading进行交互优化。
2024-06-04 16:18:17 +08:00
alwayrun
e2e82dc3f3 fix: 修复物料基础组件 BaseRate 重复触发 change 事件问题 (#254) 2024-06-04 15:36:54 +08:00
xixiIBN5100
caca627b18 perf: 显示逻辑展示优化 (#249) 2024-06-04 15:31:30 +08:00
dayou
7ad01f6b26 feat: 问卷空间协作能力前端 (#246) 2024-06-03 18:05:48 +08:00
luch
9448d3c111 feat: 新增空间和协作功能 (#252) 2024-06-03 18:05:40 +08:00
sudoooooo
b26855de90
feat: Update README_EN.md 2024-06-03 16:47:39 +08:00
sudoooooo
725ca7bdd3 feat: 增加 README_EN.md 2024-06-03 16:45:26 +08:00
codeniu
c904fd3932 feat: 问卷列表操作栏固定 & 登录校验优化(jtest测试文件更新) (#241)
* refactor: 使用vue3组合式API重构登录页代码

* feat: 问卷列表操作栏固定

* feat: 登录校验优化
2024-05-30 15:32:30 +08:00
xixiIBN5100
f31cd0f773 perf: 问卷编辑页标题优化 (#240)
* refactor: 重构 src/management/pages/edit/modules 目录下组件, 使用 Vue3 组合式 API 写法

* perf: 问卷编辑页标题优化
2024-05-30 15:32:21 +08:00
sudoooooo
34cc06cd9c feat: 优化样式 2024-05-30 15:32:12 +08:00
chaorenluo
5f8896eec2 refactor:统一B,C端渲染组件,将其抽离到物料区 (#184)
* feat:抽离B,C端通用组件

* refactor: 通用组件统一渲染

* 兼容修复问题 (+1 squashed commit)
Squashed commits:
[8d168ef] refactor: 替换统一渲染组件

* refactor:统一B,C端渲染组件,将其抽离到物料区
2024-05-30 15:32:04 +08:00
alwayrun
ea342a0d0b fix: 修复题型拖拽移动问题 (#218) 2024-05-29 21:36:22 +08:00
alwayrun
1bd2968982 fix: 修复问卷编辑-活动题型移动选区未移动问题 (#187) 2024-05-29 21:27:25 +08:00
sudoooooo
3dc15aeb68
feat: Update README.md 2024-05-29 11:45:16 +08:00
sudoooooo
668e8a6ba7
feat: Update README.md 2024-05-29 10:41:40 +08:00
alwayrun
de2af7931f fix: 调整重构 setters 组件下几处 watch 初始值引发无法监听问题 (#178) 2024-05-28 18:24:36 +08:00
alwayrun
a64e820e80 fix: 题型切换 CheckboxGroup 基础设置组件状态监控导致问题 (#177) 2024-05-28 18:24:30 +08:00
alwayrun
eb6ba7a1a5 fix: 修复物料设置组件 RangeSetter 在设置最大值与最小值引发问题 (#175) 2024-05-28 18:24:21 +08:00
sudoooooo
89b69a9fa1 fix: C端背景和题型分割线 2024-05-27 21:38:14 +08:00
codeniu
dc7542de60 refactor: 使用vue3组合式API重构登录页代码 (#172) 2024-05-27 16:55:43 +08:00
sudoooooo
b18d872c66
feat: Update README.md 2024-05-27 16:47:35 +08:00
alwayrun
fd6585d80c refactor: 重构 management/pages/publishResult 目录下组件, 使用 Vue3 组合式 API 写法 (#167) 2024-05-27 16:19:15 +08:00
alwayrun
4b8bcac049 feat: 题型处于活动状态时操作侧边栏默认显示 (#157) 2024-05-27 16:12:50 +08:00
dayou
4c85fcc47e format: 代码格式化 (#160) 2024-05-24 20:47:54 +08:00
dayou
38566f1f60 fix:解决ts报错 (#110) 2024-05-24 20:46:50 +08:00
hiStephen
89d416becd refactor: Vue3 组合式 API 写法重构 (#165) 2024-05-24 20:34:19 +08:00
alwayrun
de7344b192 fix: 修复物料题型通用组件 BaseChoice 单选类型题重复触发 change 事件问题 (#164) 2024-05-24 20:34:06 +08:00
sudoooooo
39ff6acf99
feat: Update README.md 2024-05-24 11:28:49 +08:00
sudoooooo
e2687865ef
Update README.md 2024-05-24 10:20:54 +08:00
sudoooooo
fe3159105f
feat: Update README.md 2024-05-24 10:19:50 +08:00
sudoooooo
49f0bfbd71 feat: 增加类型检测 2024-05-23 17:15:15 +08:00
alwayrun
24881d7cdc fix: 修复活动题型选区多次点击重复触发 select 事件 (#155) 2024-05-23 16:41:09 +08:00
sudoooooo
627eabd8b2 fix: 修复单选题报错问题 2024-05-23 16:23:24 +08:00
alwayrun
3242ad80c4 refactor: 重构 management/components 目录下组件, 使用 Vue3 组合式 API 写法 (#151) 2024-05-23 11:54:37 +08:00
dayou
8ce6dc7607 fix: 修复attrs透传会触发两次select事件 (#138) 2024-05-23 11:54:29 +08:00
sudoooooo
0b0f78a3ed
feat: Update README.md 2024-05-23 11:37:53 +08:00
dayou
142b3b7be9 feat: 显示逻辑稳定版 (#149) 2024-05-21 21:44:25 +08:00
sudoooooo
21cba5946b feat: add format 2024-05-21 19:43:38 +08:00
sudoooooo
4f116fdcc4 feat: add branches 2024-05-21 19:43:11 +08:00
alwayrun
6c9044b457 refactor: 重构 materials/setters/widgets 目录下部分组件, 使用 Vue3 组合式 API 写法 (#146) 2024-05-21 19:29:39 +08:00
sudoooooo
e9b85f7878
feat: Update README.md 2024-05-20 20:50:36 +08:00
alwayrun
5e50a3a733 refactor: 重构 render/components 目录下部分组件, 使用 Vue3 组合式 API 写法 (#115) 2024-05-20 20:43:19 +08:00
sudoooooo
eed15cd23c feat: nginx配置 2024-05-20 20:21:25 +08:00
sudoooooo
3629796786 feat: nginx配置 2024-05-20 20:20:48 +08:00
chaorenluo
95917e22f0 fix:前端项目使用nginx服务代理,不在使用后端服务代理 (#100)
* fix:前端项目使用nginx服务代理,不在使用后端服务代理

* fix:修改备注
2024-05-20 18:48:13 +08:00
alwayrun
ac33ffa34a fix: 修复问卷编辑页最后一题处于活动状态下删除导致问题 (#141) 2024-05-20 17:50:52 +08:00
alwayrun
65884f80f6 refactor: 重构 render/App.vue, 使用 Vue3 组合式 API 写法 (#117) 2024-05-20 17:50:44 +08:00
sudoooooo
127a589b2c
feat: Update README.md 2024-05-17 15:55:45 +08:00
luch
ba3b1a64e5 fix: 修改alioss.handler中单测文件的报错 (#105) 2024-05-17 15:32:16 +08:00
luch
00d5e98712 [Feature]: 补充file模块的单测 (#102)
* feat: 补充file模块的单测

* fix: 安装types依赖
2024-05-17 15:32:08 +08:00
sudoooooo
91838194bb feat: 增加lint检测和覆盖率报告 2024-05-17 11:20:27 +08:00
sudoooooo
6319ca272e feat: 自动打开浏览器 2024-05-16 21:20:59 +08:00
nil
6350c95536 Feature/dnd (#132)
* feat: 增加拖拽添加题目效果

* feat: 手动实现题型的预览效果

* feat: 优化预览体验
2024-05-16 21:20:49 +08:00
sudoooooo
ee4049b947
feat: Update README.md 2024-05-16 14:50:25 +08:00
sudoooooo
76683371cf feat: lint 2024-05-15 20:36:13 +08:00
alwayrun
f9af6219ab refactor: 重构 render/pages 目录下三个文件, 使用 Vue3 组合式 API 写法 (#113) 2024-05-15 20:36:04 +08:00
sudoooooo
2560f0af3d
feat: Update README.md 2024-05-11 01:18:38 +08:00
sudoooooo
255bd8bab8 feat: 修改docker配置 2024-05-11 01:15:39 +08:00
Weiguo Wang
6771b831e5 feat: vue3 (#103) 2024-05-11 00:00:51 +08:00
sudoooooo
2bca93bf12
feat: Update README.md 2024-05-10 22:54:22 +08:00
sudoooooo
c3bbd35c2c
feat: Update README.md 2024-05-10 22:52:41 +08:00
sudoooooo
5d88d9ad59
feat: Update README.md 2024-05-10 21:08:39 +08:00
sudoooooo
39b25acc50
feat: Update README.md 2024-05-10 21:04:35 +08:00
sudoooooo
a58bfe79cc
feat: Update README.md 2024-05-10 10:23:05 +08:00
luch
f43b7d72d4 feat: 新增file模块 (#101) 2024-04-25 15:30:01 +08:00
luch
be81e2a863 feat: 消息模块新增参数校验 (#95) 2024-04-09 11:52:28 +08:00
sudoooooo
c5489daac3
feat: Update README.md 2024-04-09 11:46:22 +08:00
chaorenluo
78f2a7418b fix: 修复评分和nps题型非必填提示没有填写的问题 (#94)
* fix: 修复评分和nps题型非必填提示没有填写的问题
* fix: 使用添加key的方法修复必填提示
2024-04-08 22:37:10 +08:00
luch
dd1d977fbc feat: 调整字段必填,调整抽出fetch,修改单测 (#92) 2024-04-07 21:48:31 +08:00
luch
a357b49824 feat: 修改message单独一个module,修改默认json字段 (#90) 2024-04-07 21:48:20 +08:00
sudoooooo
84a3b6e6fa fix: 优化json 2024-04-07 21:48:10 +08:00
sudoooooo
0b3a8b57dd fix: 修复数据统计兼容展示处理和nps题型问题 2024-04-03 21:43:12 +08:00
chaorenluo
a39f3ed3b1 fix: getListHeadByDataList函数里面的兼容radio-nps (#89) 2024-04-03 21:26:24 +08:00
dayou
c07fc4341d chore: 更新iconfont (#80) 2024-04-03 21:26:22 +08:00
chaorenluo
05b9416cd9 feat: nps评分 (#79)
* feat: nps评分功能

* feat: nps样式添加

* feat: 添加nps评分icon

* feat: 基于修改建议修改nps评分组件

* feat: 将自定义类移入至设置器
2024-04-03 21:26:18 +08:00
sudoooooo
071afbfec1 fix: 冲突修复 2024-04-01 22:49:57 +08:00
luch
746bece538 feat: 新增数据推送功能 (#86) 2024-04-01 22:32:17 +08:00
sudoooooo
b3b5fa9fac
Update README.md 2024-03-28 10:49:31 +08:00
sudoooooo
ed56816836
feat: Update README.md 2024-03-28 10:49:05 +08:00
luch
d23924347e fix: 修改更新问卷基础信息的接口允许remark字段为空 (#84) 2024-03-27 15:48:49 +08:00
luch
15a41f1ba7 fix: 修改创建问卷允许空字符串,参数错误抛出异常 (#83) 2024-03-27 14:57:42 +08:00
sudoooooo
5c99bd759e feat: 优化时间排序 2024-03-25 10:56:30 +08:00
dayou
968576b665 feat: 皮肤设置 (#78) 2024-03-25 10:56:25 +08:00
sudoooooo
90243b9875 feat: 优化README 2024-03-20 14:18:39 +08:00
sudoooooo
f86eab9a95 feat: 修改pr模板 2024-03-18 19:37:25 +08:00
sudoooooo
4b860732c0 feat: 增加pr模板 2024-03-18 19:34:43 +08:00
sudoooooo
456df124f1 feat: 修改readme&增加issue模板 2024-03-18 19:26:15 +08:00
dayou
565e02ee5c fix: 升级lodash-es (#73) 2024-03-18 11:08:36 +08:00
luch
e4a8389cf5 feat: 完善单测 (#71) 2024-03-14 22:24:29 +08:00
sudoooooo
c868ca91c2 feat: 修改readme 2024-03-07 17:53:51 +08:00
chaorenluo
eea5418734 fix:修复h5模式下没填完进度条已满问题 (#69) 2024-03-07 15:53:42 +08:00
chaorenluo
70f5c45abe feat:新增进度条功能 (#68) 2024-03-07 15:53:36 +08:00
chaorenluo
3ef5e75cba fix:修复评分组件高级设置显示异常 (#63)
* fix:修复评分组件高级设置显示异常
---------

Co-authored-by: ljm <ljm@addcn.com>
2024-03-07 15:53:30 +08:00
luch
b8c089f3fd fix: 修改列表页筛选bug 2024-02-07 15:56:26 +08:00
sudoooooo
e5f70ad08c fix: 修复图片路径问题 2024-02-07 15:56:16 +08:00
sudoooooo
225e450bc9 feat: 修改traceid生成规则,修改readme、图片和windows兼容 2024-02-07 15:55:55 +08:00
luch
e3fa804fa8 fix: 修改返回页面路径问题 (#58) 2024-02-07 15:55:43 +08:00
luch
9390295f5b feat: 升级server到nestjs框架 2024-02-07 15:55:25 +08:00
sudoooooo
dfdc8025e9 fix: 修复已保存数据导致资源丢失问题 2024-02-05 16:37:15 +08:00
Weiguo Wang
e1f91de9ef [performance]:压缩图片,优化编辑器图片懒加载 (#59)
* chore: 压缩图片,格式改为webp

* perf: 优化编辑器首次加载速度,图片懒加载

* perf: 固定高度,优化滑动
2024-02-01 21:38:57 +08:00
luch
203537a9ce fix: 修改排序接口联调bug (#53) 2024-01-23 21:53:24 +08:00
Realabiha
0778b68ef8 feat: 问卷列表新增排序功能 (#54) 2024-01-23 21:53:24 +08:00
luch1994
43186b86ef fix: 修改路由解析问题 2024-01-19 14:22:55 +08:00
Realabiha
e34e5a606b feat: 问卷列表新增类型和状态筛选 2024-01-18 17:22:48 +08:00
sudoooooo
c32bbd9124 feat: 优化配置管理和lint内容 2024-01-17 15:16:33 +08:00
alwayrun
5fff688612 feat: 调整服务端环境变量导入机制 (#43)
1、为环境变量 process.env 增加 TypeScript 类型检测与感知
2、增加 dotenv & @types/node 处理支持 .env文件环境变量导入机制
2024-01-17 10:32:39 +08:00
luch1994
f851b0df10 feat: 修改参数不正确报错 2024-01-16 15:34:18 +08:00
dayou
cf9f00abf5 feat:列表页新增搜索功能 (#46) 2024-01-16 15:33:38 +08:00
luch1994
620011a19a feat: 问卷列表接口新增搜索功能 2024-01-16 15:33:38 +08:00
sudoooooo
54adf69db5
feat: Update README.md 2024-01-15 18:02:31 +08:00
sudoooooo
d9e0bdfb9a fix: 修复存储加密变量不存在 2024-01-11 15:38:58 +08:00
dayou
31ddefba16 feat: 列表页新增复制功能 (#42) 2024-01-11 15:38:58 +08:00
luch
908537ea0b feat: 新增复制功能 (#40) 2024-01-11 15:38:58 +08:00
luch
83cfd57245 feat: 新增回收数据存储加密 (#37) 2024-01-04 15:28:17 +08:00
luch
08f3bb0578
[Feature]: 服务端新增eslint (#35)
1. 服务端新增eslint
2. 修复所有的lint问题
3. 优化部署,把build命令放到docker构建中
2023-12-28 15:31:33 +09:00
54 changed files with 308 additions and 1641 deletions

View File

@ -1,5 +1,5 @@
# 镜像集成
FROM node:18
FROM node:18-slim
# 设置工作区间
WORKDIR /xiaoju-survey

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Copyright (C) 2023 Beijing Didi Infinity Technology and Development Co.,Ltd. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -161,7 +161,7 @@ npm run local
#### 1.Configure Database
> The project uses MongoDB: [MongoDB Guide](https://xiaojusurvey.didi.cn/docs/next/document/%E6%A6%82%E8%BF%B0/%E6%95%B0%E6%8D%AE%E5%BA%93)
> The project uses MongoDB: [MongoDB Guide](https://xiaojusurvey.didi.cn/docs/next/document/%E6%A6%82%E8%BF%B0/%E6%95%B0%E6%8D%AE%E5%BA%93#%E5%AE%89%E8%A3%85)
Configure the database, check MongoDB configuration.

View File

@ -29,7 +29,6 @@ import { SurveyHistory } from './models/surveyHistory.entity';
import { ResponseSchema } from './models/responseSchema.entity';
import { Counter } from './models/counter.entity';
import { SurveyResponse } from './models/surveyResponse.entity';
import { SurveyGroup } from './models/surveyGroup.entity';
import { ClientEncrypt } from './models/clientEncrypt.entity';
import { Word } from './models/word.entity';
import { MessagePushingTask } from './models/messagePushingTask.entity';
@ -79,7 +78,6 @@ import { Logger } from './logger';
SurveyConf,
SurveyHistory,
SurveyResponse,
SurveyGroup,
Counter,
ResponseSchema,
ClientEncrypt,

View File

@ -88,17 +88,10 @@ export interface MsgContent {
msg_9004: string;
}
export interface JumpConfig {
type: string;
link: string;
buttonText?: string;
}
export interface SubmitConf {
submitTitle: string;
confirmAgain: ConfirmAgain;
msgContent: MsgContent;
jumpConfig?: JumpConfig;
}
// 白名单类型

View File

@ -1,11 +0,0 @@
import { Entity, Column } from 'typeorm';
import { BaseEntity } from './base.entity';
@Entity({ name: 'surveyGroup' })
export class SurveyGroup extends BaseEntity {
@Column()
ownerId: string;
@Column()
name: string;
}

View File

@ -37,9 +37,6 @@ export class SurveyMeta extends BaseEntity {
@Column()
workspaceId: string;
@Column()
groupId: string;
@Column()
curStatus: {
status: RECORD_STATUS;

View File

@ -275,11 +275,6 @@ describe('DataStatisticController', () => {
again_text: '确认要提交吗?',
},
link: '',
jumpConfig: {
type: 'link',
link: '',
buttonText: '',
},
},
logicConf: {
showLogicConf: [],

View File

@ -71,11 +71,6 @@ export const mockSensitiveResponseSchema: ResponseSchema = {
is_again: true,
again_text: '确认要提交吗?',
},
jumpConfig: {
type: 'link',
link: '',
buttonText: '',
},
},
dataConf: {
dataList: [
@ -370,11 +365,6 @@ export const mockResponseSchema: ResponseSchema = {
is_again: true,
again_text: '确认要提交吗?',
},
jumpConfig: {
type: 'link',
link: '',
buttonText: '',
},
},
dataConf: {
dataList: [

View File

@ -1,132 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SurveyGroupController } from '../controllers/surveyGroup.controller';
import { SurveyGroupService } from '../services/surveyGroup.service';
import { SurveyMetaService } from '../services/surveyMeta.service';
import { HttpException } from 'src/exceptions/httpException';
import { ObjectId } from 'mongodb';
import { Logger } from 'src/logger';
jest.mock('src/guards/authentication.guard');
describe('SurveyGroupController', () => {
let controller: SurveyGroupController;
let service: SurveyGroupService;
const mockService = {
create: jest.fn(),
findAll: jest.fn(),
update: jest.fn(),
remove: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [SurveyGroupController],
providers: [
{
provide: SurveyMetaService,
useValue: {
countSurveyMetaByGroupId: jest.fn().mockResolvedValue(0),
},
},
{
provide: SurveyGroupService,
useValue: mockService,
},
{
provide: Logger,
useValue: {
error: jest.fn(),
info: jest.fn(),
},
},
],
}).compile();
controller = module.get<SurveyGroupController>(SurveyGroupController);
service = module.get<SurveyGroupService>(SurveyGroupService);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
describe('create', () => {
it('should create a survey group', async () => {
const result = {
_id: new ObjectId(),
name: 'Test Group',
ownerId: '123',
createdAt: new Date(),
updatedAt: new Date(),
}; // 确保这里返回的对象结构符合预期
jest.spyOn(service, 'create').mockResolvedValue(result);
// 创建模拟的请求对象
const req = {
user: {
_id: '123', // 模拟的用户ID
},
};
expect(await controller.create({ name: 'Test Group' }, req)).toEqual({
code: 200,
data: {
id: result._id,
},
});
expect(service.create).toHaveBeenCalledWith({
name: 'Test Group',
ownerId: req.user._id.toString(), // 这里用模拟的 req.user._id
});
});
});
describe('findAll', () => {
it('should return a list of survey groups', async () => {
const result = { total: 0, notTotal: 0, list: [], allList: [] };
jest.spyOn(service, 'findAll').mockResolvedValue(result);
const mockReq = { user: { _id: new ObjectId() } };
const mockQue = { curPage: 1, pageSize: 10, name: '' };
const userId = mockReq.user._id.toString();
expect(await controller.findAll(mockReq, mockQue)).toEqual({
code: 200,
data: result,
});
expect(service.findAll).toHaveBeenCalledWith(userId, '', 0, 10);
});
});
describe('update', () => {
it('should update a survey group', async () => {
const updatedFields = { name: 'xxx' };
const updatedResult = { raw: 'xxx', generatedMaps: [] };
const id = '1';
jest.spyOn(service, 'update').mockResolvedValue(updatedResult);
expect(await controller.updateOne(id, updatedFields)).toEqual({
code: 200,
ret: updatedResult,
});
expect(service.update).toHaveBeenCalledWith(id, updatedFields);
});
it('should throw error on invalid parameter', async () => {
const id = '1';
const invalidFields: any = {};
await expect(controller.updateOne(id, invalidFields)).rejects.toThrow(
HttpException,
);
});
});
describe('remove', () => {
it('should remove a survey group', async () => {
const id = '1';
jest.spyOn(service, 'remove').mockResolvedValue(undefined);
expect(await controller.remove(id)).toEqual({ code: 200 });
expect(service.remove).toHaveBeenCalledWith(id);
});
});
});

View File

@ -1,102 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SurveyGroupService } from '../services/surveyGroup.service';
import { SurveyGroup } from 'src/models/surveyGroup.entity';
import { SurveyMeta } from 'src/models/surveyMeta.entity';
import { getRepositoryToken } from '@nestjs/typeorm';
describe('SurveyGroupService', () => {
let service: SurveyGroupService;
const mockSurveyGroupRepository = {
create: jest.fn(),
save: jest.fn(),
findAndCount: jest.fn(),
find: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
};
const mockSurveyMetaRepository = {
updateMany: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
SurveyGroupService,
{
provide: getRepositoryToken(SurveyGroup),
useValue: mockSurveyGroupRepository,
},
{
provide: getRepositoryToken(SurveyMeta),
useValue: mockSurveyMetaRepository,
},
],
}).compile();
service = module.get<SurveyGroupService>(SurveyGroupService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('create', () => {
it('should create a survey group', async () => {
const createParams = { name: 'Test Group', ownerId: '123' };
const mockSavedGroup = { ...createParams, id: '1' };
mockSurveyGroupRepository.create.mockReturnValue(mockSavedGroup);
mockSurveyGroupRepository.save.mockResolvedValue(mockSavedGroup);
expect(await service.create(createParams)).toEqual(mockSavedGroup);
expect(mockSurveyGroupRepository.create).toHaveBeenCalledWith(
createParams,
);
expect(mockSurveyGroupRepository.save).toHaveBeenCalledWith(
mockSavedGroup,
);
});
});
describe('findAll', () => {
it('should return survey groups', async () => {
const list = [{ id: '1', name: 'Test Group', ownerId: '123' }];
const total = list.length;
mockSurveyGroupRepository.findAndCount.mockResolvedValue([list, total]);
mockSurveyGroupRepository.find.mockResolvedValue(list);
const result = await service.findAll('123', '', 0, 10);
expect(result).toEqual({ total, list, allList: list });
expect(mockSurveyGroupRepository.findAndCount).toHaveBeenCalled();
expect(mockSurveyGroupRepository.find).toHaveBeenCalled();
});
});
describe('update', () => {
it('should update a survey group', async () => {
const id = '1';
const updatedFields = { name: 'Updated Test Group' };
await service.update(id, updatedFields);
expect(mockSurveyGroupRepository.update).toHaveBeenCalledWith(id, {
...updatedFields,
updatedAt: expect.any(Date),
});
});
});
describe('remove', () => {
it('should remove a survey group', async () => {
const id = '1';
await service.remove(id);
expect(mockSurveyMetaRepository.updateMany).toHaveBeenCalledWith(
{ groupId: id },
{ $set: { groupId: null } },
);
expect(mockSurveyGroupRepository.delete).toHaveBeenCalledWith(id);
});
});
});

View File

@ -77,7 +77,6 @@ describe('SurveyMetaController', () => {
survey: {
title: reqBody.title,
remark: reqBody.remark,
groupId: null,
},
});

View File

@ -86,7 +86,6 @@ describe('SurveyMetaService', () => {
createMethod: params.createMethod,
createFrom: params.createFrom,
workspaceId: params.workspaceId,
groupId: null,
});
expect(surveyRepository.save).toHaveBeenCalledWith(newSurvey);
expect(result).toEqual(newSurvey);

View File

@ -78,7 +78,7 @@ export class SurveyController {
throw new HttpException('参数错误', EXCEPTION_CODE.PARAMETER_ERROR);
}
const { title, remark, createMethod, createFrom, groupId } = value;
const { title, remark, createMethod, createFrom } = value;
let surveyType = '',
workspaceId = null;
@ -100,7 +100,6 @@ export class SurveyController {
createMethod,
createFrom,
workspaceId,
groupId,
});
await this.surveyConfService.createSurveyConf({
surveyId: surveyMeta._id.toString(),

View File

@ -1,145 +0,0 @@
import {
Controller,
Get,
Post,
Delete,
Body,
Param,
UseGuards,
Request,
HttpCode,
Query,
} from '@nestjs/common';
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
import moment from 'moment';
import { Authentication } from 'src/guards/authentication.guard';
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
import { SurveyGroupService } from '../services/surveyGroup.service';
import { Logger } from 'src/logger';
import { HttpException } from 'src/exceptions/httpException';
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
import { CreateSurveyGroupDto } from '../dto/createSurveyGroup.dto';
import { UpdateSurveyGroupDto } from '../dto/updateSurveyGroup.dto';
import { GetGroupListDto } from '../dto/getGroupList.dto';
@ApiTags('surveyGroup')
@ApiBearerAuth()
@UseGuards(Authentication)
@Controller('api/surveyGroup')
export class SurveyGroupController {
constructor(
private readonly surveyMetaService: SurveyMetaService,
private readonly SurveyGroupService: SurveyGroupService,
private readonly logger: Logger,
) {}
@Post()
@HttpCode(200)
async create(
@Body()
reqBody: CreateSurveyGroupDto,
@Request()
req,
) {
const { error, value } = CreateSurveyGroupDto.validate(reqBody);
if (error) {
this.logger.error(`createSurveyGroup_parameter error: ${error.message}`);
throw new HttpException('参数错误', EXCEPTION_CODE.PARAMETER_ERROR);
}
const userId = req.user._id.toString();
const ret = await this.SurveyGroupService.create({
name: value.name,
ownerId: userId,
});
return {
code: 200,
data: {
id: ret._id,
},
};
}
@Get()
@HttpCode(200)
async findAll(@Request() req, @Query() queryInfo: GetGroupListDto) {
const { value, error } = GetGroupListDto.validate(queryInfo);
if (error) {
this.logger.error(`GetGroupListDto validate failed: ${error.message}`);
throw new HttpException(
`参数错误: 请联系管理员`,
EXCEPTION_CODE.PARAMETER_ERROR,
);
}
const userId = req.user._id.toString();
const curPage = Number(value.curPage);
const pageSize = Number(value.pageSize);
const skip = (curPage - 1) * pageSize;
const { total, list, allList } = await this.SurveyGroupService.findAll(
userId,
value.name,
skip,
pageSize,
);
const groupIdList = list.map((item) => item._id.toString());
const surveyTotalList = await Promise.all(
groupIdList.map((item) => {
return this.surveyMetaService.countSurveyMetaByGroupId({
groupId: item,
});
}),
);
const surveyTotalMap = groupIdList.reduce((pre, cur, index) => {
const total = surveyTotalList[index];
pre[cur] = total;
return pre;
}, {});
const notTotal = await this.surveyMetaService.countSurveyMetaByGroupId({
groupId: null,
});
return {
code: 200,
data: {
total,
list: list.map((item) => {
const id = item._id.toString();
return {
...item,
createdAt: moment(item.createdAt).format('YYYY-MM-DD HH:mm:ss'),
surveyTotal: surveyTotalMap[id] || 0,
};
}),
allList,
notTotal,
},
};
}
@Post(':id')
@HttpCode(200)
async updateOne(
@Param('id') id: string,
@Body()
reqBody: UpdateSurveyGroupDto,
) {
const { error, value } = UpdateSurveyGroupDto.validate(reqBody);
if (error) {
this.logger.error(`createSurveyGroup_parameter error: ${error.message}`);
throw new HttpException('参数错误', EXCEPTION_CODE.PARAMETER_ERROR);
}
const ret = await this.SurveyGroupService.update(id, value);
return {
code: 200,
ret,
};
}
@Delete(':id')
@HttpCode(200)
async remove(@Param('id') id: string) {
await this.SurveyGroupService.remove(id);
return {
code: 200,
};
}
}

View File

@ -48,7 +48,6 @@ export class SurveyMetaController {
title: Joi.string().required(),
remark: Joi.string().allow(null, '').default(''),
surveyId: Joi.string().required(),
groupId: Joi.string().allow(null, ''),
}).validate(reqBody, { allowUnknown: true });
if (error) {
@ -58,8 +57,6 @@ export class SurveyMetaController {
const survey = req.surveyMeta;
survey.title = value.title;
survey.remark = value.remark;
survey.groupId =
value.groupId && value.groupId !== '' ? value.groupId : null;
await this.surveyMetaService.editSurveyMeta({
survey,
@ -89,7 +86,7 @@ export class SurveyMetaController {
this.logger.error(error.message);
throw new HttpException('参数有误', EXCEPTION_CODE.PARAMETER_ERROR);
}
const { curPage, pageSize, workspaceId, groupId } = value;
const { curPage, pageSize, workspaceId } = value;
let filter = {},
order = {};
if (value.filter) {
@ -123,7 +120,6 @@ export class SurveyMetaController {
filter,
order,
workspaceId,
groupId,
surveyIdList,
});
return {

View File

@ -20,9 +20,6 @@ export class CreateSurveyDto {
@ApiProperty({ description: '问卷创建在哪个空间下', required: false })
workspaceId?: string;
@ApiProperty({ description: '问卷创建在哪个分组下', required: false })
groupId?: string;
static validate(data) {
return Joi.object({
title: Joi.string().required(),
@ -39,7 +36,6 @@ export class CreateSurveyDto {
otherwise: Joi.allow(null),
}),
workspaceId: Joi.string().allow(null, ''),
groupId: Joi.string().allow(null, ''),
}).validate(data);
}
}

View File

@ -1,13 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
import Joi from 'joi';
export class CreateSurveyGroupDto {
@ApiProperty({ description: '分组名称', required: true })
name: string;
static validate(data) {
return Joi.object({
name: Joi.string().required(),
}).validate(data);
}
}

View File

@ -1,21 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
import Joi from 'joi';
export class GetGroupListDto {
@ApiProperty({ description: '当前页码', required: true })
curPage: number;
@ApiProperty({ description: '分页', required: false })
pageSize: number;
@ApiProperty({ description: '空间名称', required: false })
name?: string;
static validate(data: Partial<GetGroupListDto>): Joi.ValidationResult {
return Joi.object({
curPage: Joi.number().required(),
pageSize: Joi.number().allow(null).default(10),
name: Joi.string().allow(null, '').optional(),
}).validate(data);
}
}

View File

@ -17,9 +17,6 @@ export class GetSurveyListDto {
@ApiProperty({ description: '空间id', required: false })
workspaceId?: string;
@ApiProperty({ description: '分组id', required: false })
groupId?: string;
static validate(data) {
return Joi.object({
curPage: Joi.number().required(),
@ -27,7 +24,6 @@ export class GetSurveyListDto {
filter: Joi.string().allow(null),
order: Joi.string().allow(null),
workspaceId: Joi.string().allow(null, ''),
groupId: Joi.string().allow(null, ''),
}).validate(data);
}
}

View File

@ -1,13 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
import Joi from 'joi';
export class UpdateSurveyGroupDto {
@ApiProperty({ description: '分组名称', required: true })
name: string;
static validate(data) {
return Joi.object({
name: Joi.string().required(),
}).validate(data);
}
}

View File

@ -1,56 +0,0 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { MongoRepository } from 'typeorm';
import { SurveyGroup } from 'src/models/surveyGroup.entity';
import { SurveyMeta } from 'src/models/surveyMeta.entity';
@Injectable()
export class SurveyGroupService {
constructor(
@InjectRepository(SurveyGroup)
private readonly SurveyGroup: MongoRepository<SurveyGroup>,
@InjectRepository(SurveyMeta)
private surveyMetaRepository: MongoRepository<SurveyMeta>,
) {}
create(params: { name: string; ownerId: string }) {
const newGroup = this.SurveyGroup.create({
...params,
});
return this.SurveyGroup.save(newGroup);
}
async findAll(userId: string, name: string, skip: number, pageSize: number) {
const [list, total] = await this.SurveyGroup.findAndCount({
skip: skip,
take: pageSize,
where: name
? { name: { $regex: name, $options: 'i' }, ownerId: userId }
: { ownerId: userId },
order: {
createdAt: -1,
},
});
const allList = await this.SurveyGroup.find({
where: { ownerId: userId },
select: ['_id', 'name'],
});
return {
total,
list,
allList,
};
}
update(id: string, updatedFields: Partial<SurveyGroup>) {
updatedFields.updatedAt = new Date();
return this.SurveyGroup.update(id, updatedFields);
}
async remove(id: string) {
const query = { groupId: id };
const update = { $set: { groupId: null } };
await this.surveyMetaRepository.updateMany(query, update);
return this.SurveyGroup.delete(id);
}
}

View File

@ -47,7 +47,6 @@ export class SurveyMetaService {
createMethod: string;
createFrom: string;
workspaceId?: string;
groupId?: string;
}) {
const {
title,
@ -58,7 +57,6 @@ export class SurveyMetaService {
createFrom,
userId,
workspaceId,
groupId,
} = params;
const surveyPath = await this.getNewSurveyPath();
const newSurvey = this.surveyRepository.create({
@ -73,7 +71,6 @@ export class SurveyMetaService {
createMethod,
createFrom,
workspaceId,
groupId: groupId && groupId !== '' ? groupId : null,
});
return await this.surveyRepository.save(newSurvey);
@ -146,18 +143,10 @@ export class SurveyMetaService {
filter: Record<string, any>;
order: Record<string, any>;
workspaceId?: string;
groupId?: string;
surveyIdList?: Array<string>;
}): Promise<{ data: any[]; count: number }> {
const {
pageNum,
pageSize,
userId,
username,
workspaceId,
groupId,
surveyIdList,
} = condition;
const { pageNum, pageSize, userId, username, workspaceId, surveyIdList } =
condition;
const skip = (pageNum - 1) * pageSize;
try {
const query: Record<string, any> = Object.assign(
@ -171,15 +160,6 @@ export class SurveyMetaService {
if (condition.filter['curStatus.status']) {
query['subStatus.status'] = RECORD_SUB_STATUS.DEFAULT;
}
if (groupId && groupId !== 'all') {
query.groupId =
groupId === 'nogrouped'
? {
$exists: true,
$eq: null,
}
: groupId;
}
if (workspaceId) {
query.workspaceId = workspaceId;
} else {
@ -248,21 +228,4 @@ export class SurveyMetaService {
});
return total;
}
async countSurveyMetaByGroupId({ groupId }) {
const total = await this.surveyRepository.count({
groupId,
$or: [
{ workspaceId: { $exists: false } },
{ workspaceId: null },
{ workspaceId: '' },
],
isDeleted: {
$ne: true,
},
'curStatus.status': {
$ne: RECORD_STATUS.REMOVED,
},
});
return total;
}
}

View File

@ -17,13 +17,11 @@ import { SurveyUIController } from './controllers/surveyUI.controller';
import { CollaboratorController } from './controllers/collaborator.controller';
import { DownloadTaskController } from './controllers/downloadTask.controller';
import { SessionController } from './controllers/session.controller';
import { SurveyGroupController } from './controllers/surveyGroup.controller';
import { SurveyConf } from 'src/models/surveyConf.entity';
import { SurveyHistory } from 'src/models/surveyHistory.entity';
import { SurveyMeta } from 'src/models/surveyMeta.entity';
import { SurveyResponse } from 'src/models/surveyResponse.entity';
import { SurveyGroup } from 'src/models/surveyGroup.entity';
import { Word } from 'src/models/word.entity';
import { Collaborator } from 'src/models/collaborator.entity';
import { DownloadTask } from 'src/models/downloadTask.entity';
@ -40,7 +38,6 @@ import { CounterService } from '../surveyResponse/services/counter.service';
import { FileService } from '../file/services/file.service';
import { DownloadTaskService } from './services/downloadTask.service';
import { SessionService } from './services/session.service';
import { SurveyGroupService } from './services/surveyGroup.service';
import { Session } from 'src/models/session.entity';
@Module({
@ -55,7 +52,6 @@ import { Session } from 'src/models/session.entity';
Counter,
DownloadTask,
Session,
SurveyGroup,
]),
ConfigModule,
SurveyResponseModule,
@ -72,7 +68,6 @@ import { Session } from 'src/models/session.entity';
CollaboratorController,
DownloadTaskController,
SessionController,
SurveyGroupController,
],
providers: [
DataStatisticService,
@ -87,7 +82,6 @@ import { Session } from 'src/models/session.entity';
DownloadTaskService,
FileService,
SessionService,
SurveyGroupService,
],
})
export class SurveyModule {}

View File

@ -39,8 +39,8 @@
"showSpliter": true,
"placeholder": "",
"isRequired": true,
"min": "",
"max": "",
"starMin": "",
"starMax": "",
"type": "radio-star",
"title": "标题2"
}

View File

@ -75,11 +75,6 @@ export const mockResponseSchema: ResponseSchema = {
is_again: true,
again_text: '确认要提交吗?',
},
jumpConfig: {
type: 'link',
link: '',
buttonText: '',
},
},
dataConf: {
dataList: [

View File

@ -78,21 +78,3 @@ export const getCollaboratorPermissions = (surveyId: string) => {
}
})
}
export const createGroup = ({ name }: any) => {
return axios.post('surveyGroup', { name })
}
export const updateGroup = ({ _id, name }: any) => {
return axios.post(`/surveyGroup/${_id}`, { name })
}
export const getGroupList = (params: any) => {
return axios.get('/surveyGroup', {
params
})
}
export const deleteGroup = (id: string) => {
return axios.delete(`/surveyGroup/${id}`)
}

View File

@ -1,14 +1,13 @@
import axios from './base'
export const getSurveyList = ({ curPage, filter, order, workspaceId, groupId }) => {
export const getSurveyList = ({ curPage, filter, order, workspaceId }) => {
return axios.get('/survey/getList', {
params: {
pageSize: 10,
curPage,
filter,
order,
workspaceId,
groupId
workspaceId
}
})
}

View File

@ -3,7 +3,6 @@
<el-select-v2
v-model="value"
filterable
class="search-name"
remote
:remote-method="remoteMethod"
clearable
@ -59,8 +58,7 @@ const value = ref('')
const selectOptions = ref<ListItem[]>([])
const loading = ref(false)
const remoteMethod = async (q: string) => {
const query = q.trim()
const remoteMethod = async (query: string) => {
if (query !== '') {
loading.value = true
const res: any = await getUserList(query)

View File

@ -115,9 +115,6 @@ const rules = {
{
trigger: 'change',
validator: (rule: any, value: IMember[], callback: Function) => {
if (value.length === 0) {
callback('请添加协作者')
}
if (value.filter((item: IMember) => !item.role.length).length) {
callback('请设置协作者对应权限')
}
@ -189,18 +186,8 @@ const handleMembersChange = (val: IMember[]) => {
}
</script>
<style lang="scss" scoped>
<style lang="scss" rel="lang/scss" scoped>
.base-form-root {
padding: 20px;
:deep(.list-wrapper .el-select) {
.el-select__placeholder {
text-align: right;
}
}
}
:deep(.el-form-item.is-error .search-name .el-select__wrapper) {
box-shadow: 0 0 0 1px var(--el-border-color) inset;
}
</style>

View File

@ -125,11 +125,6 @@ const handleCheckAll = (val: CheckboxValueType) => {
:deep(.el-select__wrapper) {
border: none;
box-shadow: none;
&:hover,
&:focus {
border: none;
box-shadow: none;
}
}
:deep(.ishovering) {
border: none;
@ -139,11 +134,11 @@ const handleCheckAll = (val: CheckboxValueType) => {
display: flex;
justify-content: flex-end;
}
// .operation-select {
// :deep(.el-select__placeholder) {
// text-align: right;
// }
// }
.operation-select {
:deep(.el-select__placeholder) {
text-align: right;
}
}
}
</style>
<style lang="scss">

View File

@ -34,25 +34,6 @@ export const spaceListConfig = {
}
}
export const groupListConfig = {
name: {
title: '分组名称',
key: 'name',
width: 200
},
surveyTotal: {
title: '问卷数',
key: 'surveyTotal',
width: 150,
tip: true
},
createdAt: {
title: '创建时间',
key: 'createdAt',
minWidth: 200
}
}
export const fieldConfig = {
type: {
title: '类型',
@ -111,16 +92,6 @@ export const noSpaceSearchDataConfig = {
desc: '可以更换条件查询试试',
img: '/imgs/icons/list-empty.webp'
}
export const noGroupDataConfig = {
title: '您还没有创建问卷分组',
desc: '赶快点击右上角立即创建问卷分组吧!',
img: '/imgs/icons/list-empty.webp'
}
export const noGroupSearchDataConfig = {
title: '没有满足该查询条件的问卷分组哦',
desc: '可以更换条件查询试试',
img: '/imgs/icons/list-empty.webp'
}
export const noSearchDataConfig = {
title: '没有满足该查询条件的问卷',
desc: '可以更换条件查询试试',

View File

@ -26,19 +26,6 @@
/>
<p class="form-item-tip">备注仅自己可见</p>
</el-form-item>
<el-form-item prop="groupId" label="问卷分组" v-if="menuType === MenuType.PersonalGroup">
<el-select
v-model="form.groupId"
placeholder="未分组"
>
<el-option
v-for="item in groupAllList"
:key="item?._id"
:label="item?.name"
:value="item?._id"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button class="create-btn" type="primary" @click="submit" :loading="!canSubmit">
开始创建
@ -50,13 +37,11 @@
<script setup lang="ts">
import { ref, reactive, computed, toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { createSurvey } from '@/management/api/survey'
import { SURVEY_TYPE_LIST } from '../types'
import { MenuType, GroupState } from '@/management/utils/workSpace'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
interface Props {
@ -68,8 +53,6 @@ const props = withDefaults(defineProps<Props>(), {
})
const workSpaceStore = useWorkSpaceStore()
const { groupAllList, menuType, groupId, workSpaceId } = storeToRefs(workSpaceStore)
const ruleForm = ref<any>(null)
const state = reactive({
@ -79,8 +62,7 @@ const state = reactive({
canSubmit: true,
form: {
title: '问卷调研',
remark: '问卷调研',
groupId: groupId.value == GroupState.All || groupId.value == GroupState.Not ? '' : groupId.value
remark: '问卷调研'
}
})
const { rules, canSubmit, form } = toRefs(state)
@ -110,8 +92,8 @@ const submit = () => {
surveyType: selectType,
...state.form
}
if (workSpaceId.value) {
payload.workspaceId = workSpaceId.value
if (workSpaceStore.workSpaceId) {
payload.workspaceId = workSpaceStore.workSpaceId
}
const res: any = await createSurvey(payload)
if (res?.code === 200 && res?.data?.id) {

View File

@ -14,7 +14,6 @@
v-for="(content, contentIndex) in item.content"
:key="`${item.key}${contentIndex}`"
:form-config="content"
v-show="isShowFormItem(content)"
>
<Component
:is="components[content.type]"
@ -83,14 +82,6 @@ const formFieldData = ref<Array<any>>([])
const init = ref<boolean>(true)
const components = shallowRef<any>(props.customComponents || {})
const isShowFormItem = (content: any) => {
if (_isFunction(content.toggleShowFn)) {
return content.toggleShowFn(props.moduleConfig)
} else {
return true
}
}
const handleFormChange = (data: any, formConfig: any) => {
//
if (_isFunction(formConfig?.valueSetter)) {

View File

@ -11,7 +11,6 @@
:list="item.questionList"
:group="{ name: DND_GROUP, pull: 'clone', put: false }"
:clone="createNewQuestion"
@end="onDragEnd"
item-key="path"
>
<template #item="{ element }">
@ -54,7 +53,7 @@ import { ref } from 'vue'
const editStore = useEditStore()
const { newQuestionIndex } = storeToRefs(editStore)
const { addQuestion, hasSetCurrentEditOne, createNewQuestion } = editStore
const { addQuestion, setCurrentEditOne, createNewQuestion } = editStore
const activeNames = ref([0, 1])
const previewImg = ref('')
@ -68,11 +67,7 @@ questionLoader.init({
const onQuestionType = ({ type }) => {
const newQuestion = createNewQuestion({ type })
addQuestion({ question: newQuestion, index: newQuestionIndex.value })
hasSetCurrentEditOne(newQuestionIndex.value)
}
const onDragEnd = (event) => {
hasSetCurrentEditOne(event.newIndex)
setCurrentEditOne(newQuestionIndex.value)
}
const showPreview = ({ snapshot }, id) => {

View File

@ -5,7 +5,7 @@
</div>
<SetterField
class="question-config-form"
label-position="left"
label-position="top"
:form-config-list="formFields"
:module-config="moduleConfig"
@form-change="handleFormChange"
@ -71,25 +71,4 @@ const handleFormChange = ({ key, value }: any) => {
.question-config-form {
padding: 30px 20px 50px 20px;
}
:deep(.group-wrap) {
margin-bottom: 0;
&:not(:last-child) {
margin-bottom: 32px;
}
.group-title {
margin-bottom: 12px;
}
.el-form-item {
margin-bottom: 16px;
.el-radio {
height: initial;
line-height: initial;
margin-bottom: initial;
}
}
}
</style>

View File

@ -5,9 +5,7 @@
<img src="/imgs/icons/success.webp" class="success-img" />
<div class="title-msg" v-safe-html="successText"></div>
</div>
<div v-if="jumpConfig.buttonText && jumpConfig.type === 'button'" class="jump-btn">
{{ jumpConfig.buttonText }}
</div>
<div class="bottom-btn"></div>
</div>
</div>
</template>
@ -19,7 +17,6 @@ interface Props {
}
const props = defineProps<Props>()
const successText = computed(() => props.moduleConfig?.msgContent?.msg_200 || '')
const jumpConfig = computed(() => props.moduleConfig?.jumpConfig || {})
</script>
<style lang="scss" scoped>
/*成功页面跳转全屏展示浮层*/
@ -53,18 +50,7 @@ const jumpConfig = computed(() => props.moduleConfig?.jumpConfig || {})
font-size: 0.36rem;
}
}
.jump-btn {
background: var(--primary-color);
width: 90%;
border-radius: 0.08rem;
padding: 0.25rem 0;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.25rem;
font-weight: 500;
margin: 0 auto;
border: none;
.bottom-btn {
height: 300px;
}
</style>

View File

@ -16,9 +16,7 @@
<script setup lang="ts">
import { watch, ref } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useEditStore } from '@/management/stores/edit'
const editStore = useEditStore()
const { setCurrentEditOne } = editStore
const routes = [
{
text: '内容设置',
@ -40,7 +38,6 @@ watch(
activeRouter,
(val: any) => {
// query
setCurrentEditOne(null)
const query = route.query
router.push({ name: val, query })
},

View File

@ -103,7 +103,7 @@ export default {
type: 'WhiteList',
custom: true, // 自定义导入高级组件
relyFunc: (data) => {
return data.whitelistType == 'CUSTOM'
return data.whitelistType === 'CUSTOM'
}
},
team_list: {
@ -112,7 +112,7 @@ export default {
type: 'TeamMemberList',
custom: true, // 自定义导入高级组件
relyFunc: (data) => {
return data.whitelistType == 'MEMBER'
return data.whitelistType === 'MEMBER'
}
},
}

View File

@ -1,7 +1,7 @@
export default {
Success: [
{
title: '提示文案',
label: '提示文案',
type: 'RichText',
key: 'msgContent.msg_200',
placeholder: '提交成功',
@ -9,46 +9,6 @@ export default {
labelStyle: {
'font-weight': 'bold'
}
},
{
title: '交卷跳转',
type: 'Customed',
key: 'jumpConfig',
content: [
{
key: 'jumpConfig.type',
type: 'RadioGroup',
value: 'link',
options: [
{
label: '跳转网页',
value: 'link'
},
{
label: '跳转按钮',
value: 'button'
},
],
},
{
key: 'jumpConfig.buttonText',
label: '按钮文案',
type: 'InputSetter',
placeholder: '请输入按钮文案',
value: '',
toggleShowFn: (data) => {
return data?.jumpConfig?.type === 'button'
},
},
{
key: 'jumpConfig.link',
label: '跳转链接',
type: 'InputSetter',
placeholder: '请输入网址',
value: '',
},
]
}
],
OverTime: [

View File

@ -98,8 +98,6 @@
:type="modifyType"
:visible="showModify"
:question-info="questionInfo"
:group-all-list="groupAllList"
:menu-type="menuType"
@on-close-codify="onCloseModify"
/>
<CooperModify :modifyId="cooperId" :visible="cooperModify" @on-close-codify="onCooperClose" />
@ -144,7 +142,7 @@ import {
const surveyListStore = useSurveyListStore()
const workSpaceStore = useWorkSpaceStore()
const { workSpaceId, groupAllList, menuType } = storeToRefs(workSpaceStore)
const { workSpaceId } = storeToRefs(workSpaceStore)
const router = useRouter()
const props = defineProps({
loading: {
@ -365,6 +363,7 @@ const onDelete = async (row) => {
type: 'warning'
})
} catch (error) {
console.log('取消删除')
return
}
@ -372,8 +371,6 @@ const onDelete = async (row) => {
if (res.code === CODE_MAP.SUCCESS) {
ElMessage.success('删除成功')
onRefresh()
workSpaceStore.getGroupList()
workSpaceStore.getSpaceList()
} else {
ElMessage.error(res.errmsg || '删除失败')
}
@ -412,8 +409,6 @@ const onCloseModify = (type) => {
questionInfo.value = {}
if (type === 'update') {
onRefresh()
workSpaceStore.getGroupList()
workSpaceStore.getSpaceList()
}
}
const onRowClick = (row) => {

View File

@ -1,245 +0,0 @@
<template>
<div class="search">
<TextSearch placeholder="请输入分组名称" :value="searchVal" @search="onSearchText" />
</div>
<div class="list-wrap" v-if="props.total">
<el-table
v-if="props.total"
ref="multipleListTable"
class="list-table"
:data="data"
empty-text="暂无数据"
row-key="_id"
header-row-class-name="tableview-header"
row-class-name="tableview-row"
cell-class-name="tableview-cell"
v-loading="loading"
:height="550"
style="width: 100%"
>
<el-table-column column-key="space" width="20" />
<el-table-column
v-for="field in fieldList"
:key="(field as any)?.key"
:label="(field as any).title"
:column-key="(field as any).key"
:width="(field as any).width"
:min-width="(field as any).width || (field as any).minWidth"
class-name="link"
>
<template #default="scope">
<template v-if="(field as any).comp">
<component :is="(field as any).comp" type="table" :value="scope.row" />
</template>
<template v-else>
<span class="cell-span">{{ scope.row[(field as any).key] }}</span>
</template>
</template>
</el-table-column>
<el-table-column
label="操作"
:width="200"
label-class-name="operation"
class-name="table-options"
>
<template #default="scope">
<div class="space-tool-bar">
<ToolBar
:data="scope.row"
:tool-width="50"
:tools="tools"
@click="handleClick"
/>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div v-else>
<EmptyIndex :data="!searchVal ? noGroupDataConfig : noGroupSearchDataConfig" />
</div>
<div class="list-pagination">
<el-pagination
v-if="props.total"
v-model:current-page="curPage"
background
@current-change="handleCurrentChange"
layout="prev, pager, next"
:total="props.total"
>
</el-pagination>
</div>
<GroupModify
v-if="showGroupModify"
type="edit"
:visible="showGroupModify"
@on-close-codify="onCloseModify"
/>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue'
import { ElMessageBox } from 'element-plus'
import 'element-plus/theme-chalk/src/message-box.scss'
import { get, map } from 'lodash-es'
import {
noGroupDataConfig,
noGroupSearchDataConfig,
groupListConfig
} from '@/management/config/listConfig'
import { MenuType } from '@/management/utils/workSpace'
import GroupModify from './GroupModify.vue'
import TextSearch from '@/management/pages/list/components/TextSearch.vue'
import EmptyIndex from '@/management/components/EmptyIndex.vue'
import ToolBar from './ToolBar.vue'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
import { useSurveyListStore } from '@/management/stores/surveyList'
const workSpaceStore = useWorkSpaceStore()
const surveyListStore = useSurveyListStore()
const showGroupModify = ref(false)
const props = defineProps({
loading: {
type: Boolean,
default: false
},
data: {
type: Array,
default: () => []
},
total: {
type: Number,
default: 0
}
})
const emit = defineEmits(['refresh'])
const fields = ['name', 'surveyTotal', 'createdAt']
const fieldList = computed(() => {
return map(fields, (f) => {
return get(groupListConfig, f, null)
})
})
const tools = ref([{
key: 'open',
label: '进入'
}, {
key: 'modify',
label: '管理'
}, {
key: 'delete',
label: '删除'
}])
const data = computed(() => {
return props.data
})
let searchVal = ref('')
let curPage = ref(1)
const emitRefresh = (page: number, name: string) => {
curPage.value = page
emit('refresh', {
curPage: page,
name
})
}
const handleCurrentChange = async (val: number) => {
emitRefresh(val, searchVal.value)
}
const onSearchText = async (value: string) => {
searchVal.value = value
emitRefresh(1, value)
}
const handleModify = (id: string) => {
workSpaceStore.getGroupDetail(id)
showGroupModify.value = true
}
const handleDelete = (id: string) => {
ElMessageBox.confirm(
'删除分组后,属于该分组的问卷将会自动更换到“未分组”下,是否确认本次删除?',
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(async () => {
await workSpaceStore.deleteGroup(id)
await workSpaceStore.getGroupList()
})
.catch(() => {})
}
const handleClick = (key: string, data: any) => {
if (key === 'modify') {
handleModify(data._id)
} else if (key === 'delete') {
handleDelete(data._id)
} else if(key === 'open') {
workSpaceStore.changeMenuType(MenuType.PersonalGroup)
workSpaceStore.changeGroup(data._id)
surveyListStore.getSurveyList({
pageSize: 10,
curPage: 1
})
}
}
const onCloseModify = () => {
showGroupModify.value = false
workSpaceStore.getGroupList()
}
defineExpose({ onCloseModify })
</script>
<style lang="scss" scoped>
.search {
display: flex;
justify-content: flex-end;
margin-bottom: 20px;
}
.list-pagination {
margin-top: 20px;
:deep(.el-pagination) {
display: flex;
justify-content: flex-end;
}
}
.list-wrap {
padding: 20px;
background: #fff;
.search {
display: flex;
}
.list-table {
:deep(.el-table__header) {
.tableview-header .el-table__cell {
.cell {
height: 24px;
color: #4a4c5b;
font-size: 14px;
}
}
}
:deep(.tableview-row) {
.tableview-cell {
height: 42px;
&.link {
cursor: pointer;
}
.cell .cell-span {
font-size: 14px;
}
}
}
}
}
</style>

View File

@ -1,119 +0,0 @@
<template>
<el-dialog
class="base-dialog-root"
:model-value="visible"
width="40%"
:title="formTitle"
@close="onClose"
>
<el-form
class="base-form-root"
ref="ruleForm"
:model="formModel"
:rules="rules"
label-position="top"
size="large"
@submit.prevent
>
<el-form-item label="分组名称" prop="name">
<el-input v-model="formModel.name" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="onClose">取消</el-button>
<el-button type="primary" class="save-btn" @click="onConfirm">
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { computed, ref, shallowRef, onMounted } from 'vue'
import { pick as _pick } from 'lodash-es'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { QOP_MAP } from '@/management/utils/constant'
import { type IGroup } from '@/management/utils/workSpace'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
const workSpaceStore = useWorkSpaceStore()
const emit = defineEmits(['on-close-codify'])
const props = defineProps({
type: String,
width: String,
visible: Boolean
})
const ruleForm = shallowRef<any>(null)
const formTitle = computed(() => {
return props.type === QOP_MAP.ADD ? '创建分组' : '管理分组'
})
const formModel = ref<Required<IGroup>>({
_id: '',
name: ''
})
const rules = {
name: [{ required: true, message: '请输入分组名称', trigger: 'blur' }]
}
const groupDetail = computed(() => {
return workSpaceStore.groupDetail
})
onMounted(() => {
if (props.type === QOP_MAP.EDIT) {
formModel.value = _pick(groupDetail.value as any, ['_id', 'name'])
}
})
const onClose = () => {
formModel.value = {
_id: '',
name: ''
}
//
workSpaceStore.setGroupDetail(null)
emit('on-close-codify')
}
const onConfirm = async () => {
ruleForm.value?.validate(async (valid: boolean) => {
if (valid) {
if (props.type === QOP_MAP.ADD) {
try {
await handleAdd()
emit('on-close-codify')
} catch (err) {
ElMessage.error('createGroup status err' + err)
}
} else {
try {
await handleUpdate()
emit('on-close-codify')
} catch (err) {
ElMessage.error('createGroup status err' + err)
}
}
} else {
return false
}
})
}
const handleUpdate = async () => {
await workSpaceStore.updateGroup(formModel.value)
}
const handleAdd = async () => {
await workSpaceStore.addGroup({ name: formModel.value.name })
}
</script>
<style lang="scss" rel="lang/scss" scoped>
.base-form-root {
padding: 20px;
}
</style>

View File

@ -21,19 +21,6 @@
<el-form-item label="备注">
<el-input v-model="current.remark" />
</el-form-item>
<el-form-item prop="groupId" label="问卷分组" v-if="menuType === MenuType.PersonalGroup">
<el-select
v-model="current.groupId"
placeholder="未分组"
>
<el-option
v-for="item in groupAllList"
:key="item._id"
:label="item.name"
:value="item._id"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
@ -48,6 +35,7 @@
<script>
import { pick as _pick } from 'lodash-es'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
@ -55,22 +43,17 @@ import { CODE_MAP } from '@/management/api/base'
import { updateSurvey, createSurvey } from '@/management/api/survey'
import { QOP_MAP } from '@/management/utils/constant'
import { MenuType } from '@/management/utils/workSpace'
export default {
name: 'ModifyDialog',
props: {
type: String,
questionInfo: Object,
width: String,
visible: Boolean,
groupAllList: Array,
menuType: String,
visible: Boolean
},
data() {
return {
QOP_MAP,
MenuType,
loadingInstance: null,
rules: {
title: [{ required: true, message: '请输入问卷标题', trigger: 'blur' }]
@ -89,8 +72,7 @@ export default {
methods: {
getCurrent(val) {
return {
..._pick(val, ['title', 'remark']),
groupId: val.groupId === null ? '' : val.groupId
..._pick(val, ['title', 'remark'])
}
},
onClose() {

View File

@ -1,16 +1,14 @@
<template>
<el-menu
:default-active="active"
:default-active="SpaceType.Personal"
class="el-menu-vertical"
ref="menuRef"
@select="handleMenu"
@open="handleMenu"
@close="handleMenu"
@select="handleSelect"
>
<template v-for="(menu, index) in props.menus" :key="menu.id">
<template v-for="(menu, index) in menus" :key="menu.id">
<el-menu-item
:class="[index === 0 ? 'bottom' : '', index > 2 ? 'sub-item' : 'main-item', active == menu.id ? 'check-item' : '' ]"
:index="menu.id.toString()"
:class="[index === 0 ? 'bottom' : '', index > 2 ? 'sub-item' : 'main-item']"
:index="menu.id"
v-if="!menu.children?.length"
>
<template #title>
@ -20,65 +18,46 @@
</div>
</template>
</el-menu-item>
<el-sub-menu v-else :index="menu.id.toString()" :class="[ active == menu.id ? 'check-item' : '' ]">
<el-menu-item-group v-else>
<template #title>
<div class="title-content sub-title main-item">
<el-menu-item :index="menu.id" class="sub-title main-item">
<div class="title-content">
<i :class="['iconfont', menu.icon]"></i>
<span>{{ menu.name }}</span>
</div>
</el-menu-item>
</template>
<el-menu-item v-for="item in menu.children" :key="item.id" :index="item.id.toString()" :class="[ active == item.id ? 'check-item' : '' ]">
<div class="title-box">
<p class="title-text">{{ item.name }}</p>
<p class="title-total">{{ item.total }}</p>
</div>
<el-menu-item v-for="item in menu.children" :key="item.id" :index="item.id">
<p>
{{ item.name }}
</p>
</el-menu-item>
</el-sub-menu>
</el-menu-item-group>
</template>
</el-menu>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ref } from 'vue'
import { type MenuItem } from '@/management/utils/workSpace'
import { MenuType } from '@/management/utils/workSpace'
import { SpaceType } from '@/management/utils/workSpace'
const menuRef = ref()
const props = withDefaults(
withDefaults(
defineProps<{
menus: Array<MenuItem>,
activeValue: string
menus: Array<MenuItem>
}>(),
{
menus: () => [],
activeValue: MenuType.PersonalGroup
menus: () => []
}
)
const active = computed({
get: () => {
return props.activeValue
},
set: () => {}
})
const emit = defineEmits(['select'])
const handleMenu = (id: string) => {
active.value = id
const handleSelect = (id: string) => {
emit('select', id)
}
</script>
<style lang="scss" scoped>
.el-sub-menu {
:deep(.el-sub-menu__icon-arrow) {
transform: rotate(-90deg) !important;
}
&.is-opened {
> :deep(.el-sub-menu__title .el-sub-menu__icon-arrow) {
transform: rotate(0deg) !important;
}
}
}
.el-menu-vertical {
border: none;
width: 200px;
@ -115,6 +94,10 @@ const handleMenu = (id: string) => {
&.sub-item {
margin: 0;
}
&.is-active {
// background-color: #F2F4F7;
background: #fef6e6 100% !important;
}
&:hover {
background-color: #f2f4f7;
}
@ -123,27 +106,6 @@ const handleMenu = (id: string) => {
align-items: center;
font-weight: 400;
}
.title-box {
width: 100%;
display: flex;
justify-content: space-between;
}
.title-text {
width: 80%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.title-total {
font-size: 14px;
color: #92949D;
text-align: right;
font-weight: 400;
}
}
:deep(.el-menu-item-group) {
> ul {
@ -166,7 +128,4 @@ const handleMenu = (id: string) => {
margin-right: 10px;
color: #faa600 !important;
}
.check-item {
background: #fef6e6 100% !important
}
</style>

View File

@ -2,75 +2,71 @@
<div class="search">
<TextSearch placeholder="请输入空间名称" :value="searchVal" @search="onSearchText" />
</div>
<template v-if="total > 0">
<div class="list-wrap">
<el-table
ref="multipleListTable"
class="list-table"
:data="data"
empty-text="暂无数据"
row-key="_id"
header-row-class-name="tableview-header"
row-class-name="tableview-row"
cell-class-name="tableview-cell"
v-loading="loading"
:height="550"
style="width: 100%"
<div class="list-wrap" v-if="props.total > 0">
<el-table
ref="multipleListTable"
class="list-table"
:data="data"
empty-text="暂无数据"
row-key="_id"
header-row-class-name="tableview-header"
row-class-name="tableview-row"
cell-class-name="tableview-cell"
v-loading="loading"
:height="550"
style="width: 100%"
>
<el-table-column column-key="space" width="20" />
<el-table-column
v-for="field in fieldList"
:key="(field as any)?.key"
:label="(field as any).title"
:column-key="(field as any).key"
:width="(field as any).width"
:min-width="(field as any).width || (field as any).minWidth"
class-name="link"
>
<el-table-column column-key="space" width="20" />
<el-table-column
v-for="field in fieldList"
:key="(field as any)?.key"
:label="(field as any).title"
:column-key="(field as any).key"
:width="(field as any).width"
:min-width="(field as any).width || (field as any).minWidth"
class-name="link"
>
<template #default="scope">
<template v-if="(field as any).comp">
<component :is="(field as any).comp" type="table" :value="scope.row" />
</template>
<template v-else>
<span class="cell-span">{{ scope.row[(field as any).key] }}</span>
</template>
<template #default="scope">
<template v-if="(field as any).comp">
<component :is="(field as any).comp" type="table" :value="scope.row" />
</template>
</el-table-column>
<el-table-column
label="操作"
:width="200"
label-class-name="operation"
class-name="table-options"
>
<template #default="scope">
<div class="space-tool-bar">
<ToolBar
:data="scope.row"
:tool-width="50"
:tools="getTools(scope.row)"
@click="handleClick"
/>
</div>
<template v-else>
<span class="cell-span">{{ scope.row[(field as any).key] }}</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="list-pagination">
<el-pagination
v-model:current-page="curPage"
background
@current-change="handleCurrentChange"
layout="prev, pager, next"
:total="props.total"
</template>
</el-table-column>
<el-table-column
label="操作"
:width="200"
label-class-name="operation"
class-name="table-options"
>
</el-pagination>
</div>
</template>
<template #default="scope">
<div class="space-tool-bar">
<ToolBar
:data="scope.row"
:tool-width="50"
:tools="getTools(scope.row)"
@click="handleClick"
/>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div v-else>
<EmptyIndex :data="!searchVal ? noSpaceDataConfig : noSpaceSearchDataConfig" />
</div>
<div class="list-pagination">
<el-pagination
v-model:current-page="curPage"
background
@current-change="handleCurrentChange"
layout="prev, pager, next"
:total="props.total"
>
</el-pagination>
</div>
<SpaceModify
v-if="showSpaceModify"
:type="modifyType"

View File

@ -55,7 +55,7 @@ import { useWorkSpaceStore } from '@/management/stores/workSpace'
import MemberSelect from '@/management/components/CooperModify/MemberSelect.vue'
const workSpaceStore = useWorkSpaceStore()
const emit = defineEmits(['on-close-codify', 'onFocus', 'change', 'blur', 'updateData'])
const emit = defineEmits(['on-close-codify', 'onFocus', 'change', 'blur'])
const props = defineProps({
type: String,
width: String,
@ -128,7 +128,6 @@ const onConfirm = async () => {
} else {
try {
await handleUpdate()
emit('updateData', formModel.value)
emit('on-close-codify', 'update')
} catch (err) {
ElMessage.error('createSpace status err' + err)

View File

@ -2,32 +2,23 @@
<div class="question-list-root">
<TopNav></TopNav>
<div class="content-wrap">
<SliderBar :menus="spaceMenus" :activeValue="activeValue" @select="handleSpaceSelect" />
<SliderBar :menus="spaceMenus" @select="handleSpaceSelect" />
<div class="list-content">
<div class="top">
<h2>
{{ tableTitle }}
{{ spaceType === SpaceType.Group ? '团队空间' : currentTeamSpace?.name || '问卷列表' }}
</h2>
<div class="operation">
<el-button
class="btn create-btn"
type="default"
@click="onSpaceCreate"
v-if="menuType === MenuType.SpaceGroup && !workSpaceId"
v-if="spaceType == SpaceType.Group"
>
<i class="iconfont icon-chuangjian"></i>
<span>创建团队空间</span>
</el-button>
<el-button
class="btn create-btn"
type="default"
@click="onGroupCreate"
v-if="menuType === MenuType.PersonalGroup && !groupId"
>
<i class="iconfont icon-chuangjian"></i>
<span>创建分组</span>
</el-button>
<el-button type="default" class="btn" @click="onSetGroup" v-if="workSpaceId && menuType === MenuType.SpaceGroup">
<el-button type="default" class="btn" @click="onSetGroup" v-if="workSpaceId">
<i class="iconfont icon-shujuliebiao"></i>
<span>团队管理</span>
</el-button>
@ -35,7 +26,7 @@
class="btn create-btn"
type="default"
@click="onCreate"
v-if="workSpaceId || groupId"
v-if="spaceType !== SpaceType.Group"
>
<i class="iconfont icon-chuangjian"></i>
<span>创建问卷</span>
@ -47,7 +38,7 @@
:data="surveyList"
:total="surveyTotal"
@refresh="fetchSurveyList"
v-if="workSpaceId || groupId"
v-if="spaceType !== SpaceType.Group"
></BaseList>
<SpaceList
ref="spaceListRef"
@ -55,30 +46,15 @@
:loading="spaceLoading"
:data="workSpaceList"
:total="workSpaceListTotal"
v-if="menuType === MenuType.SpaceGroup && !workSpaceId"
v-if="spaceType === SpaceType.Group"
></SpaceList>
<GroupList
ref="groupListRef"
@refresh="fetchGroupList"
:loading="groupLoading"
:data="groupList"
:total="groupListTotal"
v-if="menuType === MenuType.PersonalGroup && !groupId"
></GroupList>
</div>
</div>
<SpaceModify
v-if="showSpaceModify"
:type="modifyType"
:visible="showSpaceModify"
@on-close-codify="onCloseSpaceModify"
@update-data="onCloseModifyInTeamWork"
/>
<GroupModify
v-if="showGroupModify"
type="add"
:visible="showGroupModify"
@on-close-codify="onCloseGroupModify"
@on-close-codify="onCloseModify"
/>
</div>
</template>
@ -89,54 +65,25 @@ import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import BaseList from './components/BaseList.vue'
import SpaceList from './components/SpaceList.vue'
import GroupList from './components/GroupList.vue'
import SliderBar from './components/SliderBar.vue'
import SpaceModify from './components/SpaceModify.vue'
import GroupModify from './components/GroupModify.vue'
import TopNav from '@/management/components/TopNav.vue'
import { MenuType } from '@/management/utils/workSpace'
import { SpaceType } from '@/management/utils/workSpace'
import { useWorkSpaceStore } from '@/management/stores/workSpace'
import { useSurveyListStore } from '@/management/stores/surveyList'
import { type IWorkspace } from '@/management/utils/workSpace'
const workSpaceStore = useWorkSpaceStore()
const surveyListStore = useSurveyListStore()
const { surveyList, surveyTotal } = storeToRefs(surveyListStore)
const { spaceMenus, workSpaceId, groupId, menuType, workSpaceList, workSpaceListTotal, groupList, groupListTotal } =
const { spaceMenus, workSpaceId, spaceType, workSpaceList, workSpaceListTotal } =
storeToRefs(workSpaceStore)
const router = useRouter()
const tableTitle = computed(() => {
if(menuType.value === MenuType.PersonalGroup && !groupId.value) {
return '我的空间'
} else if (menuType.value === MenuType.SpaceGroup && !workSpaceId.value) {
return '团队空间'
} else {
return currentTeamSpace.value?.name || '问卷列表';
}
})
const activeValue = computed(() => {
if(workSpaceId.value !== '') {
return workSpaceId.value
} else if(groupId.value !== '') {
return groupId.value
} else if(menuType.value === MenuType.PersonalGroup) {
return MenuType.PersonalGroup
} else if(menuType.value === MenuType.SpaceGroup) {
return MenuType.SpaceGroup
} else {
return ''
}
})
const loading = ref(false)
const spaceListRef = ref<any>(null)
const spaceLoading = ref(false)
const groupLoading = ref(false)
const fetchSpaceList = async (params?: any) => {
spaceLoading.value = true
@ -145,39 +92,24 @@ const fetchSpaceList = async (params?: any) => {
spaceLoading.value = false
}
const fetchGroupList = async (params?: any) => {
groupLoading.value = true
workSpaceStore.changeWorkSpace('')
workSpaceStore.getGroupList(params)
groupLoading.value = false
}
const handleSpaceSelect = (id: MenuType | string) => {
if (groupId.value === id || workSpaceId.value === id) {
const handleSpaceSelect = (id: SpaceType | string) => {
if (id === spaceType.value || id === workSpaceId.value) {
return void 0
}
let parentMenu = undefined
switch (id) {
case MenuType.PersonalGroup:
workSpaceStore.changeMenuType(MenuType.PersonalGroup)
case SpaceType.Personal:
workSpaceStore.changeSpaceType(SpaceType.Personal)
workSpaceStore.changeWorkSpace('')
fetchGroupList()
break
case MenuType.SpaceGroup:
workSpaceStore.changeMenuType(MenuType.SpaceGroup)
case SpaceType.Group:
workSpaceStore.changeSpaceType(SpaceType.Group)
workSpaceStore.changeWorkSpace('')
fetchSpaceList()
break
default:
parentMenu = spaceMenus.value.find((parent: any) => parent.children.find((children: any) => children.id.toString() === id))
if(parentMenu != undefined) {
workSpaceStore.changeMenuType(parentMenu.id)
if(parentMenu.id === MenuType.PersonalGroup) {
workSpaceStore.changeGroup(id)
} else if (parentMenu.id === MenuType.SpaceGroup) {
workSpaceStore.changeWorkSpace(id)
}
}
workSpaceStore.changeSpaceType(SpaceType.Teamwork)
workSpaceStore.changeWorkSpace(id)
break
}
fetchSurveyList()
@ -199,7 +131,6 @@ const fetchSurveyList = async (params?: any) => {
}
onMounted(() => {
fetchGroupList()
fetchSpaceList()
fetchSurveyList()
})
@ -218,24 +149,7 @@ const onSetGroup = async () => {
showSpaceModify.value = true
}
const onCloseModifyInTeamWork = (data: IWorkspace) => {
if (activeValue.value === MenuType.SpaceGroup) {
const currentData = workSpaceList.value.find((item) => item._id === data._id)
if (currentData) {
currentData.name = data.name
currentData.memberTotal = data.members.length
currentData.description = data.description
}
const currentMenus: any = spaceMenus.value?.[1]?.children?.find(
(item: { id: string; name: string }) => item.id === data._id
)
if (currentMenus) {
currentMenus.name = data.name
}
}
}
const onCloseSpaceModify = (type: string) => {
const onCloseModify = (type: string) => {
showSpaceModify.value = false
if (type === 'update' && spaceListRef.value) {
fetchSpaceList()
@ -246,20 +160,6 @@ const onSpaceCreate = () => {
modifyType.value = 'add'
showSpaceModify.value = true
}
//
const showGroupModify = ref<boolean>(false)
const onCloseGroupModify = () => {
showGroupModify.value = false
fetchGroupList()
}
const onGroupCreate = () => {
showGroupModify.value = true
}
const onCreate = () => {
router.push('/create')
}

View File

@ -166,16 +166,10 @@ export const useEditStore = defineStore('edit', () => {
if (!questCount) {
return startIndex
}
return endIndex - 1
return endIndex
}
})
const hasSetCurrentEditOne = (value: number) => {
if(!currentEditOne.value) {
setCurrentEditOne(value)
}
}
// 题目操作:增删改
const { copyQuestion, addQuestion, deleteQuestion, moveQuestion } = useQuestionData({
questionDataList,
@ -200,7 +194,6 @@ export const useEditStore = defineStore('edit', () => {
currentEditMeta,
newQuestionIndex,
setCurrentEditOne,
hasSetCurrentEditOne,
changeCurrentEditStatus,
pageEditOne,

View File

@ -6,7 +6,7 @@ import 'element-plus/theme-chalk/src/message.scss'
import { CODE_MAP } from '@/management/api/base'
import { getSurveyList as getSurveyListReq } from '@/management/api/survey'
import { GroupState } from '@/management/utils/workSpace'
import { useWorkSpaceStore } from './workSpace'
import {
@ -150,8 +150,7 @@ export const useSurveyListStore = defineStore('surveyList', () => {
pageSize: payload?.pageSize || 10, // 默认一页10条
filter: filterString,
order: orderString,
workspaceId: workSpaceStore.workSpaceId,
groupId: workSpaceStore.groupId === GroupState.All ? '' : workSpaceStore.groupId
workspaceId: workSpaceStore.workSpaceId
}
const res: any = await getSurveyListReq(params)

View File

@ -10,16 +10,11 @@ import {
updateSpace as updateSpaceReq,
deleteSpace as deleteSpaceReq,
getSpaceList as getSpaceListReq,
getSpaceDetail as getSpaceDetailReq,
createGroup,
getGroupList as getGroupListReq,
updateGroup as updateGroupReq,
deleteGroup as deleteGroupReq
getSpaceDetail as getSpaceDetailReq
} from '@/management/api/space'
import { GroupState, MenuType } from '@/management/utils/workSpace'
import { type SpaceDetail, type SpaceItem, type IWorkspace, type IGroup, type GroupItem, } from '@/management/utils/workSpace'
import { SpaceType } from '@/management/utils/workSpace'
import { type SpaceDetail, type SpaceItem, type IWorkspace } from '@/management/utils/workSpace'
import { useSurveyListStore } from './surveyList'
@ -29,18 +24,16 @@ export const useWorkSpaceStore = defineStore('workSpace', () => {
{
icon: 'icon-wodekongjian',
name: '我的空间',
id: MenuType.PersonalGroup,
children: []
id: SpaceType.Personal
},
{
icon: 'icon-tuanduikongjian',
name: '团队空间',
id: MenuType.SpaceGroup,
id: SpaceType.Group,
children: []
}
])
const menuType = ref(MenuType.PersonalGroup)
const groupId = ref('')
const spaceType = ref(SpaceType.Personal)
const workSpaceId = ref('')
const spaceDetail = ref<SpaceDetail | null>(null)
const workSpaceList = ref<SpaceItem[]>([])
@ -57,8 +50,7 @@ export const useWorkSpaceStore = defineStore('workSpace', () => {
const workSpace = list.map((item: SpaceDetail) => {
return {
id: item._id,
name: item.name,
total: item.surveyTotal
name: item.name
}
})
workSpaceList.value = list
@ -86,19 +78,12 @@ export const useWorkSpaceStore = defineStore('workSpace', () => {
}
}
function changeMenuType(id: MenuType) {
menuType.value = id
function changeSpaceType(id: SpaceType) {
spaceType.value = id
}
function changeWorkSpace(id: string) {
workSpaceId.value = id
groupId.value = ''
surveyListStore.resetSearch()
}
function changeGroup(id: string) {
groupId.value = id
workSpaceId.value = ''
surveyListStore.resetSearch()
}
@ -141,130 +126,21 @@ export const useWorkSpaceStore = defineStore('workSpace', () => {
function setSpaceDetail(data: null | SpaceDetail) {
spaceDetail.value = data
}
// 分组
const groupList = ref<GroupItem[]>([])
const groupAllList = ref<IGroup[]>([])
const groupListTotal = ref(0)
const groupDetail = ref<GroupItem | null>(null)
async function addGroup(params: IGroup) {
const { name } = params
const res: any = await createGroup({ name })
if (res.code === CODE_MAP.SUCCESS) {
ElMessage.success('添加成功')
} else {
ElMessage.error('createGroup code err' + res.errmsg)
}
}
async function updateGroup(params: Required<IGroup>) {
const { _id, name } = params
const res: any = await updateGroupReq({ _id, name })
if (res?.code === CODE_MAP.SUCCESS) {
ElMessage.success('更新成功')
} else {
ElMessage.error(res?.errmsg)
}
}
async function getGroupList(params = { curPage: 1 }) {
try {
const res: any = await getGroupListReq(params)
if (res.code === CODE_MAP.SUCCESS) {
const { list, allList, total, notTotal } = res.data
let allTotal = notTotal
const group = list.map((item: GroupItem) => {
allTotal += item.surveyTotal
return {
id: item._id,
name: item.name,
total: item.surveyTotal,
}
})
group.unshift({
id: GroupState.All,
name: '全部' ,
total: allTotal
}, {
id: GroupState.Not,
name: '未分组' ,
total: notTotal
})
allList.unshift({
_id: '',
name: '未分组'
})
groupList.value = list
groupListTotal.value = total
spaceMenus.value[0].children = group
groupAllList.value = allList
} else {
ElMessage.error('getGroupList' + res.errmsg)
}
} catch (err) {
ElMessage.error('getGroupList' + err)
}
}
function getGroupDetail(id: string) {
try {
const data = groupList.value.find((item: GroupItem) => item._id === id)
if(data != undefined) {
groupDetail.value = data
} else {
ElMessage.error('groupDetail 未找到分组')
}
} catch (err) {
ElMessage.error('groupDetail' + err)
}
}
function setGroupDetail(data: null | GroupItem) {
groupDetail.value = data
}
async function deleteGroup(id: string) {
try {
const res: any = await deleteGroupReq(id)
if (res.code === CODE_MAP.SUCCESS) {
ElMessage.success('删除成功')
} else {
ElMessage.error(res.errmsg)
}
} catch (err: any) {
ElMessage.error(err)
}
}
return {
menuType,
spaceMenus,
groupId,
spaceType,
workSpaceId,
spaceDetail,
workSpaceList,
workSpaceListTotal,
getSpaceList,
getSpaceDetail,
changeMenuType,
changeSpaceType,
changeWorkSpace,
changeGroup,
addSpace,
deleteSpace,
updateSpace,
setSpaceDetail,
groupList,
groupAllList,
groupListTotal,
groupDetail,
addGroup,
updateGroup,
getGroupList,
getGroupDetail,
setGroupDetail,
deleteGroup
setSpaceDetail
}
})

View File

@ -7,15 +7,9 @@ export interface MenuItem {
id: string
name: string
icon?: string
total?: Number
children?: MenuItem[]
}
export type IGroup = {
_id?: string
name: string
}
export type IWorkspace = {
_id?: string
name: string
@ -35,7 +29,6 @@ export interface SpaceDetail {
name: string
currentUserId?: string
description: string
surveyTotal: number
members: IMember[]
}
@ -56,30 +49,16 @@ export interface ICollaborator {
permissions: Array<number>
}
export type GroupItem = {
_id: string,
name: string,
createdAt: string
updatedAt?: string
ownerId: string
surveyTotal: number
export enum SpaceType {
Personal = 'personal',
Group = 'group',
Teamwork = 'teamwork'
}
export enum MenuType {
PersonalGroup = 'personalGroup',
SpaceGroup = 'spaceGroup',
}
export enum UserRole {
Admin = 'admin',
Member = 'user'
}
export enum GroupState {
All = 'all',
Not = 'nogrouped'
}
// 定义角色标签映射对象
export const roleLabels: Record<UserRole, string> = {
[UserRole.Admin]: '管理员',

View File

@ -0,0 +1,147 @@
<template>
<el-dialog
v-model="whiteVisible"
title="验证"
:show-close="false"
class="verify-white-wrap"
width="315"
:close-on-press-escape="false"
:close-on-click-modal="false"
align-center
>
<template #header>
<div class="verify-white-head">
<div class="verify-white-title">验证</div>
<div v-if="whitelistTip" class="verify-white-tips">{{ whitelistTip }}</div>
</div>
</template>
<div class="verify-white-body">
<el-input
v-if="isPwd"
v-model="state.password"
class="wd255 mb16"
placeholder="请输入6位字符串类型访问密码"
/>
<el-input
v-if="isValue"
v-model="state.value"
class="wd255 mb16"
:placeholder="placeholder"
/>
<div class="submit-btn" @click="handleSubmit">验证并开始答题</div>
</div>
</el-dialog>
</template>
<script setup>
import { ref, reactive, computed, watch } from 'vue'
import { ElMessage } from 'element-plus'
import 'element-plus/theme-chalk/src/message.scss'
import { validate } from '../api/survey'
import { useSurveyStore } from '../stores/survey'
const whiteVisible = ref(false)
const surveyStore = useSurveyStore()
const state = reactive({
password: '',
value: '',
is_submit: false
})
const baseConf = computed(() => store.state.baseConf || {})
const isPwd = computed(() => baseConf.value.passwordSwitch)
const whitelistType = computed(() => baseConf.value.whitelistType)
const memberType = computed(() => baseConf.value.memberType)
const whitelistTip = computed(() => baseConf.value.whitelistTip)
const surveyPath = computed(() => store.state?.surveyPath || '')
const isValue = computed(() => {
if (!whitelistType.value) return false
return whitelistType.value != 'ALL'
})
const placeholder = computed(() => {
if (whitelistType.value == 'MEMBER') {
return '请输入用户名'
}
if (memberType.value == 'MOBILE') {
return '请输入手机号'
}
if (memberType.value == 'EMAIL') {
return '请输入邮箱'
}
return ''
})
const handleSubmit = async () => {
if (state.is_submit) return
const params = {
surveyPath: surveyPath.value
}
if (isValue.value) {
params.whitelist = state.value
}
if (isPwd.value) {
params.password = state.password
}
const res = await validate(params)
if (res.code != 200) {
ElMessage.error(res.errmsg || '验证失败')
return
}
whiteVisible.value = false
surveyStore.setWhiteData(params)
}
watch(
() => baseConf.value,
() => {
if (whiteVisible.value) return
if (isValue.value || isPwd.value) {
whiteVisible.value = true
}
}
)
</script>
<style lang="scss" scoped>
.verify-white-wrap {
.verify-white-body {
padding: 0 14px;
}
.verify-white-head {
padding: 0 14px;
margin-bottom: 8px;
margin-top: 2px;
}
.mb16 {
margin-bottom: 16px;
}
.verify-white-tips {
text-align: center;
margin-top: 8px;
font-size: 14px;
color: #92949d;
}
.verify-white-title {
font-size: 16px;
color: #292a36;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
}
.submit-btn {
background: #faa600;
border-radius: 2px;
width: 255px;
height: 32px;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
margin-top: 4px;
margin-bottom: 14px;
}
}
</style>

View File

@ -16,17 +16,13 @@
>
重新填写
</router-link>
<a v-if="showJumpButton" :href="jumpConfig.link" class="jump-btn">
{{ jumpConfig.buttonText }}
</a>
</div>
<LogoIcon :logo-conf="logoConf" :readonly="true" />
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, watchEffect } from 'vue'
import { computed } from 'vue'
import { useSurveyStore } from '../stores/survey'
// @ts-ignore
import communalLoader from '@materials/communals/communalLoader.js'
@ -41,20 +37,6 @@ const successMsg = computed(() => {
const msgContent = (surveyStore?.submitConf as any)?.msgContent || {}
return msgContent?.msg_200 || '提交成功'
})
const jumpConfig = computed(() => {
return (surveyStore?.submitConf as any)?.jumpConfig || {}
})
const showJumpButton = ref(false)
watchEffect(() => {
const { jumpConfig } = (surveyStore?.submitConf || {}) as any
if (jumpConfig?.type === 'link' && jumpConfig?.link) {
window.location.href = jumpConfig.link
}
showJumpButton.value = jumpConfig?.type === 'button' && jumpConfig?.buttonText
})
</script>
<style lang="scss" scoped>
@import '@/render/styles/variable.scss';
@ -105,20 +87,5 @@ watchEffect(() => {
text-decoration: underline;
display: block;
}
.jump-btn {
background: var(--primary-color);
width: 90%;
border-radius: 0.08rem;
padding: 0.2rem 0;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.3rem;
font-weight: 500;
margin: 0.5rem auto 0;
border: none;
}
}
</style>