diff --git a/.mimocode/.cron-lock b/.mimocode/.cron-lock index bf7d9c6..6df44ec 100644 --- a/.mimocode/.cron-lock +++ b/.mimocode/.cron-lock @@ -1 +1 @@ -{"pid":4264,"startedAt":1784510683025} \ No newline at end of file +{"pid":26096,"startedAt":1787887230707} \ No newline at end of file diff --git a/.mimocode/login-payload.json b/.mimocode/login-payload.json new file mode 100644 index 0000000..c910f3b --- /dev/null +++ b/.mimocode/login-payload.json @@ -0,0 +1 @@ +{"tenant_name":"连云港云泽广告传媒有限公司","account":"hero920103","password":"920103","lot_number":"test","pass_token":"test","gen_time":"test","captcha_output":"test"} diff --git a/.mimocode/position-page.png b/.mimocode/position-page.png new file mode 100644 index 0000000..ec38ea9 Binary files /dev/null and b/.mimocode/position-page.png differ diff --git a/.mimocode/position-page2.png b/.mimocode/position-page2.png new file mode 100644 index 0000000..029f044 Binary files /dev/null and b/.mimocode/position-page2.png differ diff --git a/.mimocode/position-page3.png b/.mimocode/position-page3.png new file mode 100644 index 0000000..01bc5a9 Binary files /dev/null and b/.mimocode/position-page3.png differ diff --git a/.mimocode/position-page4.png b/.mimocode/position-page4.png new file mode 100644 index 0000000..cc8933b Binary files /dev/null and b/.mimocode/position-page4.png differ diff --git a/backend/src/api/contactOA.js b/backend/src/api/contactOA.js new file mode 100644 index 0000000..194591f --- /dev/null +++ b/backend/src/api/contactOA.js @@ -0,0 +1,91 @@ +import request from '@/utils/request' + +// 通讯录相关接口 + +// 获取通讯录列表 +export function getContactList(params) { + return request({ + url: '/backend/erp/contact/list', + method: 'get', + params + }) +} + +// 获取通讯录详情 +export function getContactDetail(id) { + return request({ + url: `/backend/erp/contact/detail/${id}`, + method: 'get' + }) +} + +// 创建联系人 +export function createContact(data) { + return request({ + url: '/backend/erp/contact/create', + method: 'post', + data + }) +} + +// 更新联系人 +export function updateContact(id, data) { + return request({ + url: `/backend/erp/contact/update/${id}`, + method: 'post', + data + }) +} + +// 删除联系人 +export function deleteContact(id) { + return request({ + url: `/backend/erp/contact/delete/${id}`, + method: 'delete' + }) +} + +// 收藏/取消收藏 +export function starContact(id, starred) { + return request({ + url: `/backend/erp/contact/star/${id}`, + method: 'post', + data: { is_starred: starred } + }) +} + +// 全量同步员工到通讯录 +export function syncAllContacts(params) { + return request({ + url: '/backend/erp/contact/syncAll', + method: 'post', + params + }) +} + +// 获取通讯录组织树 +export function getContactOrgTree(params) { + return request({ + url: '/backend/erp/contact/orgTree', + method: 'get', + params + }) +} + +// 获取组织架构列表(用于选择器) +export function getOrganizationList(params) { + return request({ + url: '/backend/erp/getOrganization', + method: 'get', + params + }) +} + +// 获取职位列表(用于选择器,可按部门筛选) +export function getPositionList(params) { + return request({ + url: '/backend/erp/getPosition', + method: 'get', + params + }) +} diff --git a/backend/src/router/index.js b/backend/src/router/index.js index 794ab77..c370127 100644 --- a/backend/src/router/index.js +++ b/backend/src/router/index.js @@ -76,6 +76,18 @@ const staticMainChildren = [ component: () => import("@/views/apps/oa/organization/index.vue"), meta: { requiresAuth: true, title: "组织架构", modulePath: "/apps/oa" } }, + { + path: "/apps/oa/employee", + name: "Employee", + component: () => import("@/views/apps/oa/employee/index.vue"), + meta: { requiresAuth: true, title: "人员管理", modulePath: "/apps/oa" } + }, + { + path: "/apps/oa/position", + name: "Position", + component: () => import("@/views/apps/oa/position/index.vue"), + meta: { requiresAuth: true, title: "职位管理", modulePath: "/apps/oa" } + }, { path: "/tools/passwordStore", name: "BackendPasswordStore", diff --git a/backend/src/views/apps/oa/contact/components/contactDetailDialog.vue b/backend/src/views/apps/oa/contact/components/contactDetailDialog.vue new file mode 100644 index 0000000..9a22a72 --- /dev/null +++ b/backend/src/views/apps/oa/contact/components/contactDetailDialog.vue @@ -0,0 +1,208 @@ + + + + + diff --git a/backend/src/views/apps/oa/contact/components/contactEditDialog.vue b/backend/src/views/apps/oa/contact/components/contactEditDialog.vue new file mode 100644 index 0000000..40b7a18 --- /dev/null +++ b/backend/src/views/apps/oa/contact/components/contactEditDialog.vue @@ -0,0 +1,383 @@ + + + + + diff --git a/backend/src/views/apps/oa/contact/index.vue b/backend/src/views/apps/oa/contact/index.vue new file mode 100644 index 0000000..58ad639 --- /dev/null +++ b/backend/src/views/apps/oa/contact/index.vue @@ -0,0 +1,645 @@ + + + + + diff --git a/backend/src/views/apps/oa/employee/index.vue b/backend/src/views/apps/oa/employee/index.vue new file mode 100644 index 0000000..a6ac880 --- /dev/null +++ b/backend/src/views/apps/oa/employee/index.vue @@ -0,0 +1,366 @@ + + + + + diff --git a/backend/src/views/apps/oa/organization/components/employeeEditDialog.vue b/backend/src/views/apps/oa/organization/components/employeeEditDialog.vue index 17e8219..65313a7 100644 --- a/backend/src/views/apps/oa/organization/components/employeeEditDialog.vue +++ b/backend/src/views/apps/oa/organization/components/employeeEditDialog.vue @@ -96,12 +96,26 @@ - + :loading="positionLoading" + placeholder="请选择职位" + filterable + allow-create + default-first-option + clearable + style="width: 100%" + > + + +
+ 可下拉选择职位表中职位,也可直接输入新职位 +
@@ -187,7 +201,7 @@ diff --git a/backend/src/views/apps/oa/organization/components/orgEditDialog.vue b/backend/src/views/apps/oa/organization/components/orgEditDialog.vue index 5bb7b49..fd95222 100644 --- a/backend/src/views/apps/oa/organization/components/orgEditDialog.vue +++ b/backend/src/views/apps/oa/organization/components/orgEditDialog.vue @@ -195,8 +195,9 @@ const title = computed(() => props.isEdit ? '编辑组织' : '新建组织') const loadOrgOptions = async () => { try { - const data = await getOrganizationList() - orgOptions.value = buildOrgTree(data) + const res = await getOrganizationList() + const data = res?.data || res || [] + orgOptions.value = buildOrgTree(Array.isArray(data) ? data : []) } catch (error) { ElMessage.error(error?.message || '加载组织列表失败') } @@ -204,8 +205,9 @@ const loadOrgOptions = async () => { const loadEmployeeOptions = async () => { try { - const data = await getEmployeeList() - employeeOptions.value = data.map(item => ({ + const res = await getEmployeeList() + const data = res?.data || res || [] + employeeOptions.value = (Array.isArray(data) ? data : []).map(item => ({ id: item.id, name: item.name })) @@ -272,15 +274,19 @@ const initForm = () => { leader_id: props.formData.leader_id || null } } else { - form.value = emptyForm() + // 新建:保留父组件预填值(如添加子组织时预设的上级组织) + form.value = { + ...emptyForm(), + ...props.formData + } } } -watch(() => props.modelValue, (newVal) => { +watch(() => props.modelValue, async (newVal) => { if (newVal) { + // 先加载下拉选项再回填表单,确保已有值能正确映射label + await Promise.all([loadOrgOptions(), loadEmployeeOptions()]) initForm() - loadOrgOptions() - loadEmployeeOptions() } }, { immediate: true }) diff --git a/backend/src/views/apps/oa/organization/index.vue b/backend/src/views/apps/oa/organization/index.vue index 4eceed1..804f94b 100644 --- a/backend/src/views/apps/oa/organization/index.vue +++ b/backend/src/views/apps/oa/organization/index.vue @@ -37,38 +37,31 @@