diff --git a/web/.eslintrc.cjs b/web/.eslintrc.cjs index 50ee96f9..b44e7cfc 100644 --- a/web/.eslintrc.cjs +++ b/web/.eslintrc.cjs @@ -11,5 +11,11 @@ module.exports = { ], parserOptions: { ecmaVersion: 'latest' + }, + rules: { + 'no-empty-pattern': 'off', + "vue/multi-word-component-names": ["error", { + "ignores": ["index"] + }] } } diff --git a/web/components.d.ts b/web/components.d.ts index 8a826169..8824b169 100644 --- a/web/components.d.ts +++ b/web/components.d.ts @@ -19,6 +19,9 @@ declare module 'vue' { ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElInput: typeof import('element-plus/es')['ElInput'] ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] + ElMenu: typeof import('element-plus/es')['ElMenu'] + ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] + ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] ElOption: typeof import('element-plus/es')['ElOption'] ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] @@ -27,6 +30,7 @@ declare module 'vue' { ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElSelect: typeof import('element-plus/es')['ElSelect'] + ElSelectV2: typeof import('element-plus/es')['ElSelectV2'] ElSlider: typeof import('element-plus/es')['ElSlider'] ElSwitch: typeof import('element-plus/es')['ElSwitch'] ElTable: typeof import('element-plus/es')['ElTable'] @@ -44,6 +48,7 @@ declare module 'vue' { IEpDelete: typeof import('~icons/ep/delete')['default'] IEpLoading: typeof import('~icons/ep/loading')['default'] IEpMinus: typeof import('~icons/ep/minus')['default'] + IEpMore: typeof import('~icons/ep/more')['default'] IEpPlus: typeof import('~icons/ep/plus')['default'] IEpQuestionFilled: typeof import('~icons/ep/question-filled')['default'] IEpRank: typeof import('~icons/ep/rank')['default'] diff --git a/web/src/management/api/space.ts b/web/src/management/api/space.ts new file mode 100644 index 00000000..24de4466 --- /dev/null +++ b/web/src/management/api/space.ts @@ -0,0 +1,75 @@ +import axios from './base' + +// 空间 +export const createSpace = ({ name, description, members }: any) => { + return axios.post('/workspace', { name, description, members }) +} + +export const updateSpace = ({ workspaceId, name, description, members }: any) => { + return axios.post(`/workspace/${workspaceId}`, { name, description, members }) +} + +export const getSpaceList = () => { + return axios.get('/workspace') +} + +export const getSpaceDetail = (workspaceId: string) => { + return axios.get(`/workspace/${workspaceId}`) +} + +export const deleteSpace = (workspaceId: string) => { + return axios.delete(`/workspace/${workspaceId}`) +} + +export const getUserList = (username: string) => { + return axios.get(`/user/getUserList`, { + params: { + username + } + }) +} + +// 协作权限列表 +export const getPermissionList = () => { + return axios.get('collaborator/getPermissionList') +} + +export const saveCollaborator = ({ surveyId, collaborators }: any) => { + return axios.post('collaborator/batchSave', { + surveyId, + collaborators + }) +} + +// 添加协作人 +export const addCollaborator = ({ surveyId, userId, permissions }: any) => { + return axios.post('collaborator', { + surveyId, + userId, + permissions + }) +} +// 更新问卷协作信息 +export const updateCollaborator = ({ surveyId, userId, permissions }: any) => { + return axios.post('collaborator/changeUserPermission', { + surveyId, + userId, + permissions + }) +} +// 获取问卷协作信息 +export const getCollaborator = (surveyId: string) => { + return axios.get(`collaborator`, { + params: { + surveyId + } + }) +} +// 获取问卷协作权限 +export const getCollaboratorPermissions = (surveyId: string) => { + return axios.get(`collaborator/permissions`, { + params: { + surveyId + } + }) +} diff --git a/web/src/management/api/survey.js b/web/src/management/api/survey.js index 7a3d36d4..8cbc1444 100644 --- a/web/src/management/api/survey.js +++ b/web/src/management/api/survey.js @@ -1,12 +1,13 @@ import axios from './base' -export const getSurveyList = ({ curPage, filter, order }) => { +export const getSurveyList = ({ curPage, filter, order, workspaceId }) => { return axios.get('/survey/getList', { params: { pageSize: 10, curPage, filter, - order + order, + workspaceId } }) } diff --git a/web/src/management/components/LeftMenu.vue b/web/src/management/components/LeftMenu.vue index 12bb3b52..7f631fe6 100644 --- a/web/src/management/components/LeftMenu.vue +++ b/web/src/management/components/LeftMenu.vue @@ -1,19 +1,40 @@ - - diff --git a/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue b/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue index 08874d2a..ca0c0975 100644 --- a/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue +++ b/web/src/management/pages/edit/modules/logicModule/components/ConditionView.vue @@ -49,7 +49,7 @@ diff --git a/web/src/management/pages/list/components/MemberList.vue b/web/src/management/pages/list/components/MemberList.vue new file mode 100644 index 00000000..50b9f7f0 --- /dev/null +++ b/web/src/management/pages/list/components/MemberList.vue @@ -0,0 +1,76 @@ + + + diff --git a/web/src/management/pages/list/components/MemberSelect.vue b/web/src/management/pages/list/components/MemberSelect.vue new file mode 100644 index 00000000..a334250b --- /dev/null +++ b/web/src/management/pages/list/components/MemberSelect.vue @@ -0,0 +1,93 @@ + + + + diff --git a/web/src/management/pages/list/components/MoreTool.vue b/web/src/management/pages/list/components/MoreTool.vue new file mode 100644 index 00000000..c32aa9df --- /dev/null +++ b/web/src/management/pages/list/components/MoreTool.vue @@ -0,0 +1,87 @@ + + + diff --git a/web/src/management/pages/list/components/OperationSelect.vue b/web/src/management/pages/list/components/OperationSelect.vue new file mode 100644 index 00000000..79b9a333 --- /dev/null +++ b/web/src/management/pages/list/components/OperationSelect.vue @@ -0,0 +1,156 @@ + + + + diff --git a/web/src/management/pages/list/components/SliderBar.vue b/web/src/management/pages/list/components/SliderBar.vue new file mode 100644 index 00000000..5b7cd064 --- /dev/null +++ b/web/src/management/pages/list/components/SliderBar.vue @@ -0,0 +1,130 @@ + + + + diff --git a/web/src/management/pages/list/components/SpaceList.vue b/web/src/management/pages/list/components/SpaceList.vue new file mode 100644 index 00000000..96d3263c --- /dev/null +++ b/web/src/management/pages/list/components/SpaceList.vue @@ -0,0 +1,171 @@ + + + diff --git a/web/src/management/pages/list/components/SpaceModify.vue b/web/src/management/pages/list/components/SpaceModify.vue new file mode 100644 index 00000000..c670e1a4 --- /dev/null +++ b/web/src/management/pages/list/components/SpaceModify.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/web/src/management/pages/list/components/StateModule.vue b/web/src/management/pages/list/components/StateModule.vue index 13fa4daa..01fa7696 100644 --- a/web/src/management/pages/list/components/StateModule.vue +++ b/web/src/management/pages/list/components/StateModule.vue @@ -1,7 +1,7 @@ diff --git a/web/src/management/pages/list/components/TextButton.vue b/web/src/management/pages/list/components/TextButton.vue index ab1c57fb..f4a8efdf 100644 --- a/web/src/management/pages/list/components/TextButton.vue +++ b/web/src/management/pages/list/components/TextButton.vue @@ -9,59 +9,38 @@ - diff --git a/web/src/management/pages/list/components/TextSelect.vue b/web/src/management/pages/list/components/TextSelect.vue index e3ca453b..a71bfd27 100644 --- a/web/src/management/pages/list/components/TextSelect.vue +++ b/web/src/management/pages/list/components/TextSelect.vue @@ -12,33 +12,28 @@ - diff --git a/web/src/management/pages/list/config/index.js b/web/src/management/pages/list/config/index.js index f2f85029..5576d50a 100644 --- a/web/src/management/pages/list/config/index.js +++ b/web/src/management/pages/list/config/index.js @@ -5,6 +5,35 @@ export const type = { register: '在线报名' } +export const spaceListConfig = { + name: { + title: '空间名称', + key: 'name', + width: 300 + }, + surveyTotal: { + title: '问卷数', + key: 'surveyTotal', + width: 150, + tip: true + }, + memberTotal: { + title: '成员数', + key: 'memberTotal', + width: 150 + }, + owner: { + title: '所有者', + key: 'owner', + width: 150 + }, + createDate: { + title: '创建时间', + key: 'createDate', + minWidth: 200 + } +} + export const fieldConfig = { type: { title: '类型', diff --git a/web/src/management/pages/list/index.vue b/web/src/management/pages/list/index.vue index 722865b3..3a86203a 100644 --- a/web/src/management/pages/list/index.vue +++ b/web/src/management/pages/list/index.vue @@ -1,45 +1,159 @@ - @@ -47,7 +161,8 @@ export default { .question-list-root { height: 100%; background-color: #f6f7f9; - .login-status { + + .top-nav { background: #fff; color: #4a4c5b; padding: 0 20px; @@ -55,10 +170,25 @@ export default { display: flex; justify-content: space-between; align-items: center; - .logo-img { - width: 90px; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04); + .left { + display: flex; + align-items: center; + width: calc(100% - 200px); + .logo-img { + width: 90px; + height: fit-content; + padding-right: 20px; + } + .el-menu { + width: 100%; + height: 56px; + border: none !important; + :deep(.el-menu-item, .is-active) { + border: none !important; + } + } } - .login-info { display: flex; align-items: center; @@ -78,28 +208,46 @@ export default { color: #faa600; } } - - .list-content { + .content-wrap { + position: relative; height: calc(100% - 56px); - padding: 20px; + } + .list-content { + position: relative; + height: 100%; + width: 100%; + padding: 32px 32px 32px 232px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: scroll; .top { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; + .operation { + flex: 0 1 auto; + display: flex; + } h2 { font-size: 18px; } .create-btn { + background: #4a4c5b; + } + .space-btn { + background: $primary-color; + } + .btn { width: 132px; height: 32px; display: flex; justify-content: center; align-items: center; - background: #4a4c5b; + color: #fff; .icon-chuangjian { diff --git a/web/src/management/router/index.ts b/web/src/management/router/index.ts index 919cb688..e6a2652e 100644 --- a/web/src/management/router/index.ts +++ b/web/src/management/router/index.ts @@ -1,6 +1,9 @@ import { createRouter, createWebHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' import { useStore } from 'vuex' +import { SurveyPermissions } from '@/management/utils/types/workSpace' +import { ElMessage } from 'element-plus' +import 'element-plus/theme-chalk/src/message.scss' const routes: RouteRecordRaw[] = [ { @@ -19,7 +22,8 @@ const routes: RouteRecordRaw[] = [ { path: '/survey/:id/edit', meta: { - needLogin: true + needLogin: true, + premissions: [SurveyPermissions.SurveyManage] }, name: 'QuestionEdit', component: () => import('../pages/edit/index.vue'), @@ -89,7 +93,8 @@ const routes: RouteRecordRaw[] = [ path: '/survey/:id/analysis', name: 'analysisPage', meta: { - needLogin: true + needLogin: true, + premissions: [SurveyPermissions.DataManage] }, component: () => import('../pages/analysis/AnalysisPage.vue') }, @@ -97,7 +102,8 @@ const routes: RouteRecordRaw[] = [ path: '/survey/:id/publish', name: 'publish', meta: { - needLogin: true + needLogin: true, + premissions: [SurveyPermissions.SurveyManage] }, component: () => import('../pages/publish/PublishPage.vue') }, @@ -125,7 +131,7 @@ const router = createRouter({ routes }) -router.beforeEach((to, from, next) => { +router.beforeEach(async (to, from, next) => { const store = useStore() if (!store.state.user?.initialized) { store?.dispatch('user/init') @@ -135,7 +141,24 @@ router.beforeEach((to, from, next) => { } if (to.meta.needLogin) { if (store?.state?.user?.hasLogined) { - next() + if (to.meta.premissions) { + const params = to.params + await store.dispatch('fetchCooperPermissions', params.id) + if ( + (to.meta.premissions as []).some((permission) => + store.state?.cooperPermissions?.includes(permission) + ) + ) { + next() + } else { + ElMessage.warning('您没有该问卷的相关协作权限') + next({ + name: 'survey' + }) + } + } else { + next() + } } else { next({ name: 'login', @@ -149,4 +172,17 @@ router.beforeEach((to, from, next) => { } }) +// router.afterEach(async (to, from) => { +// const store = useStore() +// if (to.meta.premissions) { +// const params = to.params +// await store.dispatch('fetchCooperPermissions', params.id) +// if (!(to.meta.premissions as []).some((permission) => store.state?.cooperPermissions?.includes(permission))) { +// ElMessage.warning('您没有该问卷的相关协作权限') +// router.push({ +// name: 'survey' +// }) +// } +// } +// }) export default router diff --git a/web/src/management/store/actions.js b/web/src/management/store/actions.js index 91071b4c..7652fb26 100644 --- a/web/src/management/store/actions.js +++ b/web/src/management/store/actions.js @@ -1,4 +1,6 @@ import { getBannerData } from '@/management/api/skin.js' +import { getCollaboratorPermissions } from '@/management/api/space.ts' +import { CODE_MAP } from '../api/base' export default { async getBannerData({ state, commit }) { @@ -9,5 +11,12 @@ export default { if (res.code === 200) { commit('setBannerList', res.data) } + }, + async fetchCooperPermissions({ commit }, id) { + const res = await getCollaboratorPermissions(id) + console.log(res.data) + if (res.code === CODE_MAP.SUCCESS) { + commit('setCooperPermissions', res.data.permissions) + } } } diff --git a/web/src/management/store/index.js b/web/src/management/store/index.js index 69d22b47..c0ca999b 100644 --- a/web/src/management/store/index.js +++ b/web/src/management/store/index.js @@ -1,7 +1,7 @@ import { createStore } from 'vuex' import edit from './edit' import user from './user' - +import list from './list' import actions from './actions' import mutations from './mutations' import state from './state' @@ -13,6 +13,7 @@ export default createStore({ actions, modules: { edit, - user + user, + list } }) diff --git a/web/src/management/store/list/index.js b/web/src/management/store/list/index.js new file mode 100644 index 00000000..e347bebd --- /dev/null +++ b/web/src/management/store/list/index.js @@ -0,0 +1,258 @@ +import { + createSpace, + getSpaceList, + getSpaceDetail, + updateSpace, + deleteSpace +} from '@/management/api/space' +import { CODE_MAP } from '@/management/api/base' +import { ElMessage } from 'element-plus' +import 'element-plus/theme-chalk/src/message.scss' +import { getSurveyList as surveyList } from '@/management/api/survey' +import { set } from 'lodash-es' +import { SpaceType } from '@/management/utils/types/workSpace' + +export default { + namespaced: true, + state: { + // 空间管理 + spaceMenus: [ + { + icon: 'icon-wodekongjian', + name: '我的空间', + id: SpaceType.Personal + }, + { + icon: 'icon-tuanduikongjian', + name: '团队空间', + id: SpaceType.Group, + children: [ + // { + // name: '小桔问卷调研团队', + // id: 'xxxx', + // } + ] + } + ], + spaceType: SpaceType.Personal, + workSpaceId: '', + spaceDetail: null, + teamSpaceList: [], + // 列表管理 + surveyList: [], + surveyTotal: 0, + searchVal: '', + selectValueMap: { + surveyType: '', + 'curStatus.status': '' + }, + buttonValueMap: { + 'curStatus.date': '', + createDate: -1 + } + }, + getters: { + listFliter(state) { + return [ + { + comparator: '', + condition: [ + { + field: 'title', + value: state.searchVal, + comparator: '$regex' + } + ] + }, + { + comparator: '', + condition: [ + { + field: 'curStatus.status', + value: state.selectValueMap['curStatus.status'] + } + ] + }, + { + comparator: '', + condition: [ + { + field: 'surveyType', + value: state.selectValueMap.surveyType + } + ] + } + ] + }, + listOrder(state) { + const { buttonValueMap } = state + return Object.entries(buttonValueMap) + .filter(([, effectValue]) => effectValue) + .reduce((prev, item) => { + const [effectKey, effectValue] = item + prev.push({ field: effectKey, value: effectValue }) + return prev + }, []) + } + }, + mutations: { + updateSpaceMenus(state, teamSpace) { + // 更新空间列表下的团队空间 + set(state, 'spaceMenus[1].children', teamSpace) + }, + changeSpaceType(state, spaceType) { + state.spaceType = spaceType + }, + changeWorkSpace(state, workSpaceId) { + // 切换空间清除筛选条件 + this.commit('list/reserSelectValueMap') + this.commit('list/reserButtonValueMap') + this.commit('list/setSearchVal', '') + state.workSpaceId = workSpaceId + }, + setSpaceDetail(state, data) { + state.spaceDetail = data + }, + setTeamSpaceList(state, data) { + state.teamSpaceList = data + }, + setSurveyList(state, list) { + state.surveyList = list + }, + setSurveyTotal(state, total) { + state.surveyTotal = total + }, + setSearchVal(state, data) { + state.searchVal = data + }, + reserSelectValueMap(state) { + state.selectValueMap = { + surveyType: '', + 'curStatus.status': '' + } + }, + changeSelectValueMap(state, { key, value }) { + state.selectValueMap[key] = value + }, + reserButtonValueMap(state) { + state.buttonValueMap = { + 'curStatus.date': '', + createDate: -1 + } + }, + changeButtonValueMap(state, { key, value }) { + state.buttonValueMap[key] = value + } + }, + actions: { + async getSpaceList({ commit }) { + try { + const res = await getSpaceList() + + if (res.code === CODE_MAP.SUCCESS) { + const { list } = res.data + const teamSpace = list.map((item) => { + return { + id: item._id, + name: item.name + } + }) + commit('setTeamSpaceList', list) + commit('updateSpaceMenus', teamSpace) + } else { + ElMessage.error('getSpaceList' + res.errmsg) + } + } catch (err) { + ElMessage.error('getSpaceList' + err) + } + }, + async addSpace({}, params) { + const res = await createSpace({ + name: params.name, + description: params.description, + members: params.members + }) + + if (res.code === CODE_MAP.SUCCESS) { + ElMessage.success('添加成功') + } else { + ElMessage.error('createSpace code err' + res.errmsg) + } + }, + async getSpaceDetail({ state, commit }, id) { + try { + const workspaceId = id || state.workSpaceId + const res = await getSpaceDetail(workspaceId) + if (res.code === CODE_MAP.SUCCESS) { + commit('setSpaceDetail', res.data) + } else { + ElMessage.error('getSpaceList' + res.errmsg) + } + } catch (err) { + ElMessage.error('getSpaceList' + err) + } + }, + async updateSpace({}, params) { + const res = await updateSpace({ + workspaceId: params._id, + name: params.name, + description: params.description, + members: params.members + }) + + if (res.code === CODE_MAP.SUCCESS) { + ElMessage.success('更新成功') + } else { + ElMessage.error(res.errmsg) + } + }, + async deleteSpace({}, workspaceId) { + try { + const res = await deleteSpace(workspaceId) + + if (res.code === CODE_MAP.SUCCESS) { + ElMessage.success('删除成功') + } else { + ElMessage.error(res.errmsg) + } + } catch (err) { + ElMessage.error(err) + } + }, + async getSurveyList({ state, getters, commit }, payload) { + const filterString = JSON.stringify( + getters.listFliter.filter((item) => { + return item.condition[0].value + }) + ) + const orderString = JSON.stringify(getters.listOrder) + try { + let params = { + curPage: payload?.curPage || 1, + pageSize: payload?.pageSize || 10, // 默认一页10条 + filter: filterString, + order: orderString, + workspaceId: state.workSpaceId + } + // if(payload?.order) { + // params.order = payload.order + // } + // if(payload.filter) { + // params.filter = payload.filter + // } + // if(payload?.workspaceId) { + // params.workspaceId = payload.workspaceId + // } + const res = await surveyList(params) + if (res.code === CODE_MAP.SUCCESS) { + commit('setSurveyList', res.data.data) + commit('setSurveyTotal', res.data.count) + } else { + ElMessage.error(res.errmsg) + } + } catch (error) { + ElMessage.error('getSurveyList status' + error) + } + } + } +} diff --git a/web/src/management/store/mutations.js b/web/src/management/store/mutations.js index 4995fdc0..0bf45451 100644 --- a/web/src/management/store/mutations.js +++ b/web/src/management/store/mutations.js @@ -1,5 +1,8 @@ export default { setBannerList(state, data) { state.bannerList = data + }, + setCooperPermissions(state, data) { + state.cooperPermissions = data } } diff --git a/web/src/management/store/state.js b/web/src/management/store/state.js index 54246623..8ef14c4d 100644 --- a/web/src/management/store/state.js +++ b/web/src/management/store/state.js @@ -1,3 +1,5 @@ +import { SurveyPermissions } from '@/management/utils/types/workSpace' export default { - bannerList: [] + bannerList: [], + cooperPermissions: Object.values(SurveyPermissions) } diff --git a/web/src/management/styles/icon.scss b/web/src/management/styles/icon.scss index dcef1b00..c1cae880 100644 --- a/web/src/management/styles/icon.scss +++ b/web/src/management/styles/icon.scss @@ -1,9 +1,9 @@ @font-face { font-family: 'iconfont'; /* Project id 4263849 */ src: - url('//at.alicdn.com/t/c/font_4263849_xndlbqcha3l.woff2?t=1711101684869') format('woff2'), - url('//at.alicdn.com/t/c/font_4263849_xndlbqcha3l.woff?t=1711101684869') format('woff'), - url('//at.alicdn.com/t/c/font_4263849_xndlbqcha3l.ttf?t=1711101684869') format('truetype'); + url('//at.alicdn.com/t/c/font_4263849_xfsn9z31epc.woff2?t=1716556097756') format('woff2'), + url('//at.alicdn.com/t/c/font_4263849_xfsn9z31epc.woff?t=1716556097756') format('woff'), + url('//at.alicdn.com/t/c/font_4263849_xfsn9z31epc.ttf?t=1716556097756') format('truetype'); } .iconfont { @@ -131,3 +131,9 @@ .icon-NPSpingfen::before { content: '\e6e7'; } +.icon-wodekongjian::before { + content: '\e6ee'; +} +.icon-tuanduikongjian::before { + content: '\e6ec'; +} diff --git a/web/src/management/utils/constant.js b/web/src/management/utils/constant.js index b3d7ab2c..f48115f0 100644 --- a/web/src/management/utils/constant.js +++ b/web/src/management/utils/constant.js @@ -1,8 +1,10 @@ // 问卷操作枚举 export const QOP_MAP = { + ADD: 'add', COPY: 'copy', EDIT: 'edit' } + export const qAbleList = ['radio', 'checkbox', 'binary-choice', 'vote'] export const operatorOptions = [ { diff --git a/web/src/management/utils/types/workSpace.ts b/web/src/management/utils/types/workSpace.ts new file mode 100644 index 00000000..e6ca90d7 --- /dev/null +++ b/web/src/management/utils/types/workSpace.ts @@ -0,0 +1,59 @@ +export interface ListItem { + value: string + label: string +} + +export interface MenuItem { + id: string + name: string + icon?: string + children?: MenuItem[] +} + +export type IWorkspace = { + id?: string + name: string + description: string + members: IMember[] +} +export type IMember = { + userId: string + username: string + role: any + _id?: string +} + +export enum SpaceType { + Personal = 'personal', + Group = 'group', + Teamwork = 'teamwork' +} +export enum UserRole { + Admin = 'admin', + Member = 'user' +} + +// 定义角色标签映射对象 +export const roleLabels: Record = { + [UserRole.Admin]: '管理员', + [UserRole.Member]: '成员' +} + +export interface ICollaborator { + _id?: string + userId: string + username: string + permissions: Array +} + +export enum SurveyPermissions { + SurveyManage = 'SURVEY_CONF_MANAGE', + DataManage = 'SURVEY_RESPONSE_MANAGE', + CollaboratorManage = 'SURVEY_COOPERATION_MANAGE' +} +// 定义协作者权限标签映射对象 +export const surveyPermissionsLabels: Record = { + [SurveyPermissions.SurveyManage]: '问卷管理', + [SurveyPermissions.DataManage]: '数据管理', + [SurveyPermissions.CollaboratorManage]: '协作管理' +} diff --git a/web/src/materials/communals/widgets/HeaderContent/Components/HeaderVideo.jsx b/web/src/materials/communals/widgets/HeaderContent/Components/HeaderVideo.jsx index 98cfdc87..bbf90356 100644 --- a/web/src/materials/communals/widgets/HeaderContent/Components/HeaderVideo.jsx +++ b/web/src/materials/communals/widgets/HeaderContent/Components/HeaderVideo.jsx @@ -45,7 +45,7 @@ export default defineComponent({ return (
-