diff --git a/src/api/okr/meeting.js b/src/api/okr/meeting.js index 6cdaad4..df17772 100644 --- a/src/api/okr/meeting.js +++ b/src/api/okr/meeting.js @@ -43,3 +43,19 @@ export const getMeetingPage = (params) => { // headers: { 'instance-id': 1016 } }) } + +// 刷新微信群列表 +export const refreshWxGroupList = () => { + return request.get({ + url: '/admin-api/system/wx/reFreshWeChatGroupList' + // headers: { 'instance-id': 1016 } + }) +} + +// 获取微信群聊列表 +export const getWxGroupList = () => { + return request.get({ + url: '/admin-api/system/wx/getWeChatGroupList' + // headers: { 'instance-id': 1016 } + }) +} diff --git a/src/permission.js b/src/permission.js index 5ded0f7..c008a26 100644 --- a/src/permission.js +++ b/src/permission.js @@ -49,7 +49,10 @@ router.beforeEach(async (to, from, next) => { }) const redirectPath = from.query.redirect || to.path const redirect = decodeURIComponent(redirectPath) - const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect } + const nextData = + to.path === redirect + ? { ...to, replace: true, query: to.query } + : { path: redirect, query: to.query } next(nextData) } else { next() diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index b563980..a72bc20 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -139,6 +139,16 @@ const remainingRouter: AppRouteRecordRaw[] = [ noTagsView: true } }, + { + path: '/meeting-summary', + component: () => import('@/views/OKR/Meeting/MeetingSummary.vue'), + name: 'MeetingSummary', + meta: { + hidden: true, + title: '会议纪要', + noTagsView: true + } + }, { path: '/sso', component: () => import('@/views/Login/Login.vue'), diff --git a/src/views/Basic/Dept/DeptForm.vue b/src/views/Basic/Dept/DeptForm.vue index d3c9931..ead6293 100644 --- a/src/views/Basic/Dept/DeptForm.vue +++ b/src/views/Basic/Dept/DeptForm.vue @@ -33,6 +33,7 @@ @@ -136,13 +137,17 @@ const open = async (type: string, id?: number) => { try { formData.value = await DeptApi.getDept(id) formData.value.remark = formData.value.remark || '' + formData.value.leaderUserId = formData.value.leaderUserId?.map((it) => it + '') || [] } finally { formLoading.value = false } } // 获得用户列表 getEmployeeSimpleList().then((data) => { - employeeOptions.value = data + employeeOptions.value = data.map((it) => ({ + ...it, + id: it.id + '' + })) }) //实例 getSimpleAppList().then((data) => { @@ -186,7 +191,7 @@ const resetForm = () => { parentId: undefined, name: undefined, sort: 1, - leaderUserId: undefined, + leaderUserId: [], status: CommonStatusEnum.ENABLE, remark: undefined, instanceId: undefined diff --git a/src/views/Home/FalseDiligenceReport/index.vue b/src/views/Home/FalseDiligenceReport/index.vue index b7c1396..877e173 100644 --- a/src/views/Home/FalseDiligenceReport/index.vue +++ b/src/views/Home/FalseDiligenceReport/index.vue @@ -267,14 +267,18 @@ async function getList() { return pre.concat(cur.userDingAttendanceRespVOList) }, []) } else { - tableList.value = data.list.map((it, index) => ({ - ...it, - userDingAttendanceRespVOList: it.userDingAttendanceRespVOList.sort((pre, cur) => - pre.employeeName.localeCompare(cur.employeeName) - ), - id: index + 1, - edit: it.status == 1 ? '2' : '0' - })) + tableList.value = data.list.map((it, index) => { + const arr = it.userDingAttendanceRespVOList.filter((user) => user.needAttendance) + return { + ...it, + userDingAttendanceRespVOList: multiFieldSort(arr, [ + { key: 'dept' }, + { key: 'employeeName' } + ]), + id: index + 1, + edit: it.status == 1 ? '2' : '0' + } + }) } total.value = data.total } catch (err) { @@ -284,6 +288,32 @@ async function getList() { } } +function multiFieldSort(arr, fields) { + return arr.sort((a, b) => { + // 遍历每个排序字段 + for (const field of fields) { + const { key, order = 'asc' } = field + const valueA = a[key] + const valueB = b[key] + + // 处理不同类型的比较 + let compareResult + if (typeof valueA === 'number' && typeof valueB === 'number') { + compareResult = valueA - valueB // 数字比较 + } else { + compareResult = String(valueA).localeCompare(String(valueB)) // 字符串比较(兼容其他类型) + } + + // 如果当前字段值不相等,直接返回比较结果(根据排序方向调整) + if (compareResult !== 0) { + return order === 'desc' ? -compareResult : compareResult + } + } + // 所有字段都相等,保持原有顺序 + return 0 + }) +} + function spanMethod({ row, columnIndex }) { if (row.userDingAttendanceRespVOList && row.userDingAttendanceRespVOList.length > 0) { if (columnIndex === 0) { diff --git a/src/views/Home/Salary/index.vue b/src/views/Home/Salary/index.vue index a8d4cd3..a35693d 100644 --- a/src/views/Home/Salary/index.vue +++ b/src/views/Home/Salary/index.vue @@ -392,9 +392,10 @@ async function getList() { } else { tableList.value = data.list.map((it, index) => ({ ...it, - userSalaryGrantRespVOList: it.userSalaryGrantRespVOList.sort((pre, cur) => - pre.name.localeCompare(cur.name) - ), + userSalaryGrantRespVOList: multiFieldSort(it.userSalaryGrantRespVOList, [ + { key: 'dept' }, + { key: 'name' } + ]), id: index + 1, edit: it.status == 1 ? '2' : '0' })) @@ -407,6 +408,32 @@ async function getList() { } } +function multiFieldSort(arr, fields) { + return arr.sort((a, b) => { + // 遍历每个排序字段 + for (const field of fields) { + const { key, order = 'asc' } = field + const valueA = a[key] + const valueB = b[key] + + // 处理不同类型的比较 + let compareResult + if (typeof valueA === 'number' && typeof valueB === 'number') { + compareResult = valueA - valueB // 数字比较 + } else { + compareResult = String(valueA).localeCompare(String(valueB)) // 字符串比较(兼容其他类型) + } + + // 如果当前字段值不相等,直接返回比较结果(根据排序方向调整) + if (compareResult !== 0) { + return order === 'desc' ? -compareResult : compareResult + } + } + // 所有字段都相等,保持原有顺序 + return 0 + }) +} + const createSalaryRef = ref() function craeteSalary() { createSalaryRef.value.open() diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 72b313a..b341aa6 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -127,6 +127,8 @@ const formLogin = ref() const { validForm } = useFormValid(formLogin) const { setLoginState, getLoginState } = useLoginState() const { currentRoute, push } = useRouter() +const route = useRoute() + const permissionStore = usePermissionStore() const redirect = ref('') const loginLoading = ref(false) @@ -217,9 +219,12 @@ const handleLogin = async (params) => { if (redirect.value.indexOf('sso') !== -1) { window.location.href = window.location.href.replace('/login?redirect=', '') } else { - push({ path: redirect.value || permissionStore.addRouters[0].path }) + push({ + path: redirect.value || permissionStore.addRouters[0].path, + query: route.redirectedFrom?.query + }) } - } catch { + } catch (err) { loginLoading.value = false } finally { setTimeout(() => { @@ -229,10 +234,12 @@ const handleLogin = async (params) => { } } +// const routerParams = ref(undefined) watch( () => currentRoute.value, - (route) => { - redirect.value = route?.query?.redirect + (route1) => { + redirect.value = route1?.redirectedFrom?.path + // routerParams.value = route?.redirectedFrom?.query }, { immediate: true diff --git a/src/views/OKR/Meeting/MeetingInfo.vue b/src/views/OKR/Meeting/MeetingInfo.vue index a0740b5..7bac230 100644 --- a/src/views/OKR/Meeting/MeetingInfo.vue +++ b/src/views/OKR/Meeting/MeetingInfo.vue @@ -4,8 +4,8 @@
{{ form.meetingId ? '修改会议' : '新增会议' }}
- 保存至草稿 - 保存 + 保存至草稿 + 保存
@@ -108,7 +108,7 @@ - + @@ -116,22 +116,22 @@ - +
@@ -149,31 +149,31 @@
- + 创建待办 不创建待办
-
+
- + + + +
@@ -246,7 +260,7 @@ const defaultProps = { const isDetail = route.query.isDetail const currentUserId = ref(undefined) -const currentContentId = ref('') // 默认选中第一个标签页 +const currentContentId = ref(0) // 默认选中第一个标签页 const summaryIdx = ref(0) // 会议纪要的索引 const toolbarConfig = { @@ -254,25 +268,24 @@ const toolbarConfig = { } onMounted(async () => { + getWxGroupOptions() await getOptions() if (route.params.id && route.params.id != 0) { // 这里可以调用API获取会议详情数据 getMeetingInfo(route.params.id) } else { - form.value.contentList = [ + form.value.meetingContentList = [ { - id: userStore.getUser.id + '', - name: userStore.getUser.nickname, - contentArr: [ + userId: userStore.getUser.id + '', + userName: userStore.getUser.nickname, + userMeetingContentList: [ { - id: crypto.randomUUID(), - title: '主要内容', content: '' } ] } ] - currentContentId.value = form.value.contentList[0].contentArr[0].id + currentContentId.value = 0 } }) @@ -287,24 +300,12 @@ function getOptions() { }) userOptions.value = employeeResp.map((it) => ({ ...it, id: it.id + '' })) form.value.expectUsers = [userStore.getUser.id + ''] // 默认添加当前用户为预约参会人员 + // form.value.actualUsers = [userStore.getUser.id + ''] currentUserId.value = userStore.getUser.id + '' // 默认选中当前用户 - // handleUserChange() }) .catch((error) => { console.error('获取数据失败:', error) }) - // // 获取OKR节点数据 - // getAllNodeTree().then((resp) => { - // peroidList.value = listToTree(resp?.tree || [], { - // id: 'nodeId', - // pid: 'parentId', - // children: 'children' - // }) - // }) - // // 获取人员数据 - // getEmployeeSimpleList().then((data) => { - // userOptions.value = data.map((it) => ({ ...it, id: it.id + '' })) - // }) } const form = ref({ @@ -320,8 +321,8 @@ const form = ref({ meetingContent: '', meetingSummary: '', absentReason: '', - contentList: [], - meetingList: [] + meetingContentList: [], + meetingSummaryList: [] }) const rules = { meetingSubject: [{ required: true, message: '请输入会议主题', trigger: 'blur' }], @@ -356,16 +357,22 @@ const getMeetingInfo = async (meetingId) => { expectEndTime: formatDate(resp.expectEndTime, 'YYYY-MM-DD HH:mm'), expectUsers: resp.expectUsers || [], actualUsers: resp.actualUsers || [], - meetingList: resp.meetingList || [ + meetingSummaryList: resp.meetingSummaryList.map((item) => ({ + ...item, + isCreateAgentWork: !!item.isCreateAgentWork + })) || [ { - meetingSummary: resp.meetingSummary || '', - userIdList: [], + summary: resp.meetingSummary || '', + agentUserList: [], endDate: '', - createWait: true + isCreateAgentWork: true } ] } - handleUserChange(resp.expectUsers) + currentContentId.value = 0 + expectUserOptions.value = userOptions.value.filter((user) => + form.value.expectUsers.some((it) => it == user.id) + ) } } catch (error) { loading.value = false @@ -373,61 +380,57 @@ const getMeetingInfo = async (meetingId) => { } } -function userTabChange(val) { - currentContentId.value = val.contentArr[0].id +const groupOptions = ref([]) + +function getWxGroupOptions() { + MeetingApi.refreshWxGroupList().then(() => { + MeetingApi.getWxGroupList() + .then((resp) => { + groupOptions.value = resp || [] + }) + .catch((error) => { + console.error('获取微信群列表失败:', error) + }) + }) +} + +function userTabChange() { + currentContentId.value = 0 } function handleTabsEdit(targetName, action) { if (action === 'add') { - form.value.contentList.forEach((item) => { - if (item.id === currentUserId.value) { - item.contentArr.push({ - id: crypto.randomUUID(), - title: '次要内容', + form.value.meetingContentList.forEach((item) => { + if (item.userId == currentUserId.value) { + item.userMeetingContentList.push({ content: '' }) } }) } else if (action === 'remove') { - form.value.contentList.forEach((item) => { - if (item.id === currentUserId.value) { - const idx = item.contentArr.findIndex((item) => item.id == targetName) - item.contentArr.splice(idx, 1) + form.value.meetingContentList.forEach((item) => { + if (item.userId == currentUserId.value) { + item.userMeetingContentList.splice(targetName, 1) // 如果删除的是当前选中的标签页,则切换到下一个标签页 - if (currentContentId.value === targetName) { - currentContentId.value = item.contentArr[idx - 1]?.id || item.contentArr[idx + 1]?.id + if (currentContentId.value == targetName) { + currentContentId.value = targetName - 1 } } }) - const tabs = editableTabs.value - let activeName = editableTabsValue.value - if (activeName === targetName) { - tabs.forEach((tab, index) => { - if (tab.name === targetName) { - const nextTab = tabs[index + 1] || tabs[index - 1] - if (nextTab) { - activeName = nextTab.name - } - } - }) - } - - editableTabsValue.value = activeName - editableTabs.value = tabs.filter((tab) => tab.name !== targetName) } } function meetingSummaryEdit(targetName, action) { if (action === 'add') { - form.value.meetingList.push({ - meetingSummary: '', - userIdList: [], + form.value.meetingSummaryList.push({ + summary: '', + agentUserList: [], endDate: '', - createWait: true + isCreateAgentWork: true }) } else if (action === 'remove') { - form.value.meetingList.splice(targetName, 1) - summaryIdx.value = 0 + form.value.meetingSummaryList.splice(targetName, 1) + summaryIdx.value = targetName - 1 } } @@ -440,19 +443,17 @@ function handleUserChange(val) { form.value.actualUsers = [...form.value.expectUsers] } // 先过滤掉不存在的参会人员 - form.value.contentList = form.value.contentList.filter((item) => { - return val.some((it) => it == item.id) + form.value.meetingContentList = form.value.meetingContentList.filter((item) => { + return val.some((it) => it == item.userId) }) // 再补充新增的 val.map((item) => { - if (!form.value.contentList.some((it) => it.id == item)) { - form.value.contentList.push({ - id: item, - name: userOptions.value.find((it) => it.id == item).name, - contentArr: [ + if (!form.value.meetingContentList.some((it) => it.userId == item)) { + form.value.meetingContentList.push({ + userId: item, + userName: userOptions.value.find((it) => it.id == item).name, + userMeetingContentList: [ { - id: crypto.randomUUID(), - title: '主要内容', content: '' } ] @@ -462,16 +463,20 @@ function handleUserChange(val) { } const router = useRouter() -async function submit() { +async function submit(isDraft = false) { // 校验表单 if (!formRef.value) return const valid = await formRef.value.validate() if (!valid) return try { + form.value.isDraft = isDraft // 提交表单数据 if (form.value.meetingId) { - if (form.value.status == 2 && !form.value.meetingSummary) { + if ( + form.value.status == 2 && + form.value.meetingSummaryList.some((it) => it.summary.trim() == '') + ) { message.error('会议结束时,会议纪要不能为空') return } @@ -479,10 +484,6 @@ async function submit() { await MeetingApi.updateMeeting(form.value) message.success('会议更新成功') } else { - if (form.value.status == 1 && !form.value.meetingContent) { - message.error('预约会议时,会议内容不能为空') - return - } form.value.actualUsers = [] // 新增会议 await MeetingApi.createMeeting(form.value) diff --git a/src/views/OKR/Meeting/MeetingSummary.vue b/src/views/OKR/Meeting/MeetingSummary.vue new file mode 100644 index 0000000..cde23ea --- /dev/null +++ b/src/views/OKR/Meeting/MeetingSummary.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/views/OKR/Meeting/index.vue b/src/views/OKR/Meeting/index.vue index 9034ba5..9ae6179 100644 --- a/src/views/OKR/Meeting/index.vue +++ b/src/views/OKR/Meeting/index.vue @@ -11,6 +11,15 @@ @keyup.enter="handleSearch" /> + + + + @@ -117,6 +127,7 @@ const message = useMessage() const searchForm = ref({ meetingSubject: undefined, + creator: undefined, status: '1', dateRange: [], nodeId: undefined,