index.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. <template>
  2. <div v-loading="pageLoading" class="app-container" :element-loading-text="loadingText">
  3. <el-tabs type="card" style="height: 400px" class="employee-tabs">
  4. <el-tab-pane label="员工信息">
  5. <PageSearch ref="searchRef" :search-config="searchConfig" @query-click="handleQueryClick"
  6. @reset-click="handleResetClick" />
  7. <PageContent ref="contentRef" :content-config="contentConfig">
  8. <template #toolbar="{ toolbarRight, onToolbar, removeIds, cols }">
  9. <CrudToolbarLeft :remove-ids="removeIds" :perm-create="['module_payment:employee:create']">
  10. <el-button v-hasPerm="['module_payment:employee:create']" type="primary" icon="Plus"
  11. @click="handleOpenDialog('create')">
  12. 添加员工
  13. </el-button>
  14. </CrudToolbarLeft>
  15. <div class="data-table__toolbar--right">
  16. <CrudToolbarRight :buttons="toolbarRight" :cols="cols" :on-toolbar="onToolbar" />
  17. </div>
  18. </template>
  19. <template #table="{ data, loading, tableRef, onSelectionChange }">
  20. <div class="data-table__content">
  21. <el-table :ref="tableRef as any" v-loading="loading" :data="data" height="100%" border @selection-change="onSelectionChange">
  22. <template #empty>
  23. <el-empty :image-size="80" description="暂无数据" />
  24. </template>
  25. <el-table-column v-if="contentCols.find((col) => col.prop === 'selection')?.show" type="selection"
  26. min-width="55" align="center" />
  27. <!-- <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_id')?.show" key="employee_id"
  28. label="员工ID" prop="employee_id" min-width="150" show-overflow-tooltip /> -->
  29. <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_name')?.show"
  30. key="employee_name" label="员工姓名" prop="employee_name" min-width="120" show-overflow-tooltip />
  31. <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_no')?.show" key="employee_no"
  32. label="员工工号" prop="employee_no" min-width="120" show-overflow-tooltip />
  33. <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_mobile')?.show"
  34. key="employee_mobile" label="手机号" prop="employee_mobile" min-width="120" />
  35. <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_email')?.show"
  36. key="employee_email" label="邮箱" prop="employee_email" min-width="150" show-overflow-tooltip />
  37. <el-table-column v-if="contentCols.find((col) => col.prop === 'status')?.show" key="status" label="激活状态"
  38. prop="status" min-width="100">
  39. <template #default="scope">
  40. <el-tag :type="STATUS_TAG_TYPE[scope.row.status]">
  41. {{ STATUS_LABEL[scope.row.status] || scope.row.status }}
  42. </el-tag>
  43. </template>
  44. </el-table-column>
  45. <el-table-column v-if="contentCols.find((col) => col.prop === 'created_time')?.show" key="created_time"
  46. label="创建时间" prop="created_time" min-width="160" sortable />
  47. <el-table-column v-if="contentCols.find((col) => col.prop === 'operation')?.show" fixed="right"
  48. label="操作" align="center" min-width="160">
  49. <template #default="scope">
  50. <el-button v-hasPerm="['module_payment:employee:detail']" type="info" size="small" link :icon="View"
  51. @click="handleOpenDialog('detail', scope.row.employee_id)">
  52. 详情
  53. </el-button>
  54. <el-button v-hasPerm="['module_payment:employee:update']" type="primary" size="small" link
  55. @click="handleOpenDialog('update', scope.row.employee_id)">
  56. 编辑
  57. </el-button>
  58. <el-button v-hasPerm="['module_payment:employee:invite']" type="success" size="small" link
  59. @click="handleGetInviteLink(scope.row)">
  60. 签约链接
  61. </el-button>
  62. </template>
  63. </el-table-column>
  64. </el-table>
  65. </div>
  66. </template>
  67. </PageContent>
  68. </el-tab-pane>
  69. <el-tab-pane label="部门信息">
  70. <PageSearch ref="deptSearchRef" :search-config="deptSearchConfig" @query-click="handleDeptQueryClick"
  71. @reset-click="handleDeptResetClick" />
  72. <PageContent ref="deptContentRef" :content-config="deptContentConfig">
  73. <template #toolbar="{ toolbarRight, onToolbar, removeIds, cols }">
  74. <CrudToolbarLeft :remove-ids="removeIds" :perm-create="['module_payment:department:create']">
  75. <el-button v-hasPerm="['module_payment:department:create']" type="primary" icon="Plus"
  76. @click="handleOpenDeptDialog('create')">
  77. 添加部门
  78. </el-button>
  79. </CrudToolbarLeft>
  80. <div class="data-table__toolbar--right">
  81. <CrudToolbarRight :buttons="toolbarRight" :cols="cols" :on-toolbar="onToolbar" />
  82. </div>
  83. </template>
  84. <template #table="{ data, loading, tableRef, onSelectionChange }">
  85. <div class="data-table__content">
  86. <el-table :ref="tableRef as any" v-loading="loading" :data="data" height="100%" border
  87. @selection-change="onSelectionChange">
  88. <template #empty>
  89. <el-empty :image-size="80" description="暂无数据" />
  90. </template>
  91. <el-table-column v-if="deptContentCols.find((col) => col.prop === 'selection')?.show" type="selection"
  92. min-width="55" align="center" />
  93. <el-table-column v-if="deptContentCols.find((col) => col.prop === 'name')?.show" key="name" label="部门名称"
  94. prop="name" min-width="150" show-overflow-tooltip />
  95. <el-table-column v-if="deptContentCols.find((col) => col.prop === 'code')?.show" key="code" label="部门编码"
  96. prop="code" min-width="120" show-overflow-tooltip />
  97. <el-table-column v-if="deptContentCols.find((col) => col.prop === 'created_time')?.show"
  98. key="created_time" label="创建时间" prop="created_time" min-width="160" sortable />
  99. <el-table-column v-if="deptContentCols.find((col) => col.prop === 'operation')?.show" fixed="right"
  100. label="操作" align="center" min-width="160">
  101. <template #default="scope">
  102. <el-button v-hasPerm="['module_payment:department:detail']" type="info" size="small" link
  103. :icon="View" @click="handleOpenDeptDialog('detail', scope.row.department_id)">
  104. 详情
  105. </el-button>
  106. <el-button v-hasPerm="['module_payment:department:update']" type="primary" size="small" link
  107. @click="handleOpenDeptDialog('update', scope.row.department_id)">
  108. 编辑
  109. </el-button>
  110. <el-button v-hasPerm="['module_payment:department:delete']" type="danger" size="small" link
  111. @click="handleDeleteDepartment(scope.row.department_id, scope.row.name)">
  112. 删除
  113. </el-button>
  114. </template>
  115. </el-table-column>
  116. </el-table>
  117. </div>
  118. </template>
  119. </PageContent>
  120. </el-tab-pane>
  121. </el-tabs>
  122. <EnhancedDialog v-model="dialogVisible.visible" :title="dialogVisible.title" @close="handleCloseDialog">
  123. <template v-if="dialogVisible.type === 'detail'">
  124. <template v-if="dialogVisible.entity === 'employee'">
  125. <EmployeeDetail :employee-id="currentEmployeeId" :enterprise-id="currentEnterpriseId" />
  126. </template>
  127. <template v-else-if="dialogVisible.entity === 'department'">
  128. <DepartmentDetail :department-id="currentDepartmentId" :enterprise-id="currentEnterpriseId" />
  129. </template>
  130. </template>
  131. <template v-else>
  132. <template v-if="dialogVisible.entity === 'employee'">
  133. <EmployeeForm ref="formRef" :type="dialogVisible.type" :employee-id="currentEmployeeId"
  134. :enterprise-id="currentEnterpriseId" @success="handleFormSuccess" />
  135. </template>
  136. <template v-else-if="dialogVisible.entity === 'department'">
  137. <DepartmentForm ref="deptFormRef" :type="dialogVisible.type" :department-id="currentDepartmentId"
  138. :enterprise-id="currentEnterpriseId || enterpriseIdFromUrl.value" @success="handleDeptFormSuccess" />
  139. </template>
  140. </template>
  141. <template #footer>
  142. <div class="dialog-footer">
  143. <template v-if="dialogVisible.entity === 'employee'">
  144. <el-button v-if="dialogVisible.type !== 'detail'" @click="handleResetForm">
  145. 重置
  146. </el-button>
  147. <el-button v-if="dialogVisible.type !== 'detail' && dialogVisible.type === 'create'" type="primary"
  148. @click="handleSaveAndAddNext">
  149. 保存并添加下一个
  150. </el-button>
  151. <el-button v-if="dialogVisible.type !== 'detail'" type="primary" @click="handleSubmit">
  152. 保存
  153. </el-button>
  154. <el-button v-else type="primary" @click="handleCloseDialog">确定</el-button>
  155. </template>
  156. <template v-else-if="dialogVisible.entity === 'department'">
  157. <el-button v-if="dialogVisible.type !== 'detail'" type="primary" @click="handleDeptSubmit">
  158. 保存
  159. </el-button>
  160. <el-button v-if="dialogVisible.type === 'create'" type="primary" @click="handleDeptSubmit(true)">
  161. 保存并添加下一个
  162. </el-button>
  163. <el-button v-else type="primary" @click="handleCloseDialog">确定</el-button>
  164. </template>
  165. <!-- <el-button @click="handleCloseDialog">取消</el-button> -->
  166. </div>
  167. </template>
  168. </EnhancedDialog>
  169. <!-- 签约链接对话框 -->
  170. <el-dialog v-model="inviteDialogVisible.visible" :title="inviteDialogVisible.title" width="600px"
  171. @close="inviteDialogVisible.data = null">
  172. <div v-if="inviteDialogVisible.data" class="invite-link-container">
  173. <el-descriptions :column="1" border>
  174. <el-descriptions-item label="邀请链接">
  175. <div class="link-item">
  176. <el-link type="primary" :href="inviteDialogVisible.data.sign_url" target="_blank">
  177. {{ inviteDialogVisible.data.sign_url }}
  178. </el-link>
  179. <el-button type="text" size="small" @click="copyInviteLink(inviteDialogVisible.data.sign_url)">
  180. 复制
  181. </el-button>
  182. </div>
  183. </el-descriptions-item>
  184. <!-- <el-descriptions-item label="小程序签约二维码">
  185. <div class="qrcode-item">
  186. <div v-if="miniAppQrCode" class="qrcode-container">
  187. <img :src="miniAppQrCode" alt="小程序签约二维码" class="qrcode" />
  188. <p class="qrcode-tip">请使用支付宝扫码</p>
  189. </div>
  190. <div v-else class="qrcode-error">
  191. 二维码生成失败
  192. </div>
  193. <el-button type="text" size="small" @click="copyInviteLink(inviteDialogVisible.data.mini_app_sign_url)">
  194. 复制链接
  195. </el-button>
  196. </div>
  197. </el-descriptions-item> -->
  198. <el-descriptions-item v-if="inviteDialogVisible.data.share_code" label="签约吱口令">
  199. <div class="link-item">
  200. <span>{{ inviteDialogVisible.data.share_code }}</span>
  201. <el-button type="text" size="small" @click="copyInviteLink(inviteDialogVisible.data.share_code)">
  202. 复制
  203. </el-button>
  204. </div>
  205. </el-descriptions-item>
  206. </el-descriptions>
  207. </div>
  208. </el-dialog>
  209. </div>
  210. </template>
  211. <script setup lang="ts">
  212. defineOptions({
  213. name: "Employee",
  214. inheritAttrs: false,
  215. });
  216. import { View } from "@element-plus/icons-vue";
  217. import EmployeeAPI, {
  218. EmployeePageQuery,
  219. STATUS_TAG_TYPE,
  220. STATUS_LABEL,
  221. } from "@/api/module_payment/employee";
  222. import DepartmentAPI, {
  223. DepartmentPageQuery,
  224. DEPARTMENT_STATUS_TAG_TYPE,
  225. DEPARTMENT_STATUS_LABEL,
  226. } from "@/api/module_payment/department";
  227. import CrudToolbarLeft from "@/components/CURD/CrudToolbarLeft.vue";
  228. import CrudToolbarRight from "@/components/CURD/CrudToolbarRight.vue";
  229. import PageSearch from "@/components/CURD/PageSearch.vue";
  230. import PageContent from "@/components/CURD/PageContent.vue";
  231. import EnhancedDialog from "@/components/CURD/EnhancedDialog.vue";
  232. import EmployeeDetail from "./components/EmployeeDetail.vue";
  233. import EmployeeForm from "./components/EmployeeForm.vue";
  234. import DepartmentDetail from "./components/DepartmentDetail.vue";
  235. import DepartmentForm from "./components/DepartmentForm.vue";
  236. import type { ISearchConfig, IContentConfig } from "@/components/CURD/types";
  237. import { useCrudList } from "@/components/CURD/useCrudList";
  238. import { useLoadingAction } from "@/composables/useLoadingAction";
  239. import { useRoute } from "vue-router";
  240. import { ref, reactive, computed } from "vue";
  241. import { ElMessage, ElMessageBox } from "element-plus";
  242. import { useEnterpriseStore } from "@/store/modules/enterprise.store";
  243. const route = useRoute();
  244. const { searchRef, contentRef, handleQueryClick, handleResetClick, refreshList } = useCrudList();
  245. const { searchRef: deptSearchRef, contentRef: deptContentRef, handleQueryClick: handleDeptQueryClick, handleResetClick: handleDeptResetClick, refreshList: refreshDeptList } = useCrudList();
  246. const formRef = ref();
  247. const deptFormRef = ref();
  248. const { pageLoading, loadingText, execute: loadingExecute } = useLoadingAction();
  249. const enterpriseIdFromUrl = computed(() => route.query.enterprise_id as string | undefined);
  250. const searchConfig = reactive<ISearchConfig>({
  251. permPrefix: "module_payment:employee",
  252. colon: true,
  253. isExpandable: true,
  254. showNumber: 3,
  255. form: { labelWidth: "auto" },
  256. formItems: [
  257. {
  258. prop: "employee_name",
  259. label: "员工姓名",
  260. type: "input",
  261. attrs: { placeholder: "请输入员工姓名", clearable: true },
  262. },
  263. {
  264. prop: "employee_mobile",
  265. label: "手机号",
  266. type: "input",
  267. attrs: { placeholder: "请输入手机号", clearable: true },
  268. },
  269. {
  270. prop: "employee_no",
  271. label: "员工工号",
  272. type: "input",
  273. attrs: { placeholder: "请输入员工工号", clearable: true },
  274. },
  275. ],
  276. });
  277. const dialogVisible = reactive({
  278. title: "",
  279. visible: false,
  280. type: "create" as "create" | "update" | "detail",
  281. entity: "employee" as "employee" | "department",
  282. });
  283. const inviteDialogVisible = reactive({
  284. visible: false,
  285. title: "员工签约激活链接",
  286. data: null as any,
  287. });
  288. const useEnterprise = useEnterpriseStore();
  289. const currentEmployeeId = ref<string>("");
  290. const currentDepartmentId = ref<string>("");
  291. const currentEnterpriseId = computed(() => enterpriseIdFromUrl.value || useEnterprise.getCurrentEnterprise?.enterprise_id || "");
  292. // 部门搜索配置
  293. const deptSearchConfig = reactive<ISearchConfig>({
  294. permPrefix: "module_payment:department",
  295. colon: true,
  296. isExpandable: true,
  297. showNumber: 3,
  298. form: { labelWidth: "auto" },
  299. formItems: [
  300. {
  301. prop: "name",
  302. label: "部门名称",
  303. type: "input",
  304. attrs: { placeholder: "请输入部门名称", clearable: true },
  305. },
  306. // {
  307. // prop: "code",
  308. // label: "部门编码",
  309. // type: "input",
  310. // attrs: { placeholder: "请输入部门编码", clearable: true },
  311. // },
  312. // {
  313. // prop: "status",
  314. // label: "状态",
  315. // type: "select",
  316. // options: Object.entries(DEPARTMENT_STATUS_LABEL).map(([value, label]) => ({
  317. // label,
  318. // value,
  319. // })),
  320. // attrs: { placeholder: "请选择状态", clearable: true },
  321. // },
  322. ],
  323. });
  324. // 部门列表列配置
  325. const deptContentCols = reactive<
  326. Array<{
  327. prop?: string;
  328. label?: string;
  329. show?: boolean;
  330. }>
  331. >([
  332. { prop: "selection", label: "选择框", show: false },
  333. // { prop: "index", label: "序号", show: true },
  334. { prop: "name", label: "部门名称", show: true },
  335. // { prop: "code", label: "部门编码", show: true },
  336. // { prop: "parent_name", label: "上级部门", show: true },
  337. // { prop: "leader_employee_name", label: "部门负责人", show: true },
  338. // { prop: "sort_order", label: "排序值", show: true },
  339. // { prop: "status", label: "状态", show: true },
  340. { prop: "created_time", label: "创建时间", show: true },
  341. { prop: "operation", label: "操作", show: true },
  342. ]);
  343. const contentCols = reactive<
  344. Array<{
  345. prop?: string;
  346. label?: string;
  347. show?: boolean;
  348. }>
  349. >([
  350. { prop: "selection", label: "选择框", show: false },
  351. { prop: "index", label: "序号", show: true },
  352. { prop: "employee_name", label: "员工姓名", show: true },
  353. { prop: "employee_no", label: "员工工号", show: true },
  354. { prop: "employee_id", label: "员工ID", show: true },
  355. { prop: "employee_mobile", label: "手机号", show: true },
  356. { prop: "employee_email", label: "邮箱", show: true },
  357. { prop: "status", label: "激活状态", show: true },
  358. { prop: "created_time", label: "创建时间", show: true },
  359. { prop: "operation", label: "操作", show: true },
  360. ]);
  361. const contentConfig = reactive<IContentConfig<EmployeePageQuery>>({
  362. permPrefix: "module_payment:employee",
  363. pk: "employee_id",
  364. cols: contentCols as IContentConfig["cols"],
  365. hideColumnFilter: false,
  366. toolbar: [],
  367. defaultToolbar: ["refresh", "filter", "import", "export"],
  368. pagination: {
  369. pageSize: 10,
  370. pageSizes: [10, 20, 30, 50],
  371. },
  372. request: { page_no: "page", page_size: "page_size" },
  373. indexAction: async (params) => {
  374. const query: EmployeePageQuery = {
  375. page_no: params.page_no,
  376. page_size: params.page_size,
  377. };
  378. const eid = enterpriseIdFromUrl.value || useEnterprise.getCurrentEnterprise?.enterprise_id;
  379. if (eid) query.enterprise_id = eid;
  380. if (params.employee_name) query.employee_name = params.employee_name;
  381. if (params.employee_mobile) query.employee_mobile = params.employee_mobile;
  382. if (params.employee_no) query.employee_no = params.employee_no;
  383. const res = await EmployeeAPI.listEmployee(query);
  384. return {
  385. list: res.data.data?.items || [],
  386. total: Number(res.data.data?.total) || 0,
  387. };
  388. },
  389. });
  390. // 部门列表配置
  391. const deptContentConfig = reactive<IContentConfig<DepartmentPageQuery>>({
  392. permPrefix: "module_payment:department",
  393. pk: "department_id",
  394. cols: deptContentCols as IContentConfig["cols"],
  395. hideColumnFilter: false,
  396. toolbar: [],
  397. defaultToolbar: ["refresh", "filter", "import", "export"],
  398. pagination: {
  399. pageSize: 10,
  400. pageSizes: [10, 20, 30, 50],
  401. },
  402. request: { page_no: "page", page_size: "page_size" },
  403. initialParams: computed(() => ({
  404. enterprise_id: enterpriseIdFromUrl.value,
  405. })) as Record<string, unknown>,
  406. indexAction: async (params) => {
  407. const query: DepartmentPageQuery = {
  408. page_no: params.page_no,
  409. page_size: params.page_size,
  410. };
  411. if (params.enterprise_id) query.enterprise_id = params.enterprise_id;
  412. if (params.name) query.department_name = params.name;
  413. if (params.code) query.department_code = params.code;
  414. if (params.status) query.status = params.status;
  415. const res = await DepartmentAPI.listDepartment(query);
  416. // 转换数据结构以匹配前端表格显示
  417. const items = res.data.data?.items.map((item: any) => ({
  418. department_id: item.department_id,
  419. name: item.department_name,
  420. code: item.department_code,
  421. parent_id: item.parent_department_id,
  422. parent_name: '', // 可以根据parent_id查询上级部门名称
  423. leader_employee_name: item.leader_employee_name,
  424. sort_order: item.sort_order,
  425. status: item.status,
  426. created_time: item.created_time,
  427. updated_time: item.updated_time
  428. })) || [];
  429. return {
  430. list: items,
  431. total: Number(res.data.data?.total) || 0,
  432. };
  433. },
  434. });
  435. function handleOpenDialog(type: "create" | "update" | "detail", employeeId: string) {
  436. dialogVisible.type = type;
  437. dialogVisible.entity = "employee";
  438. currentEmployeeId.value = employeeId;
  439. if (type === "create") {
  440. dialogVisible.title = "添加员工";
  441. } else if (type === "update") {
  442. dialogVisible.title = "编辑员工";
  443. } else {
  444. dialogVisible.title = "员工详情";
  445. }
  446. dialogVisible.visible = true;
  447. }
  448. function handleOpenDeptDialog(type: "create" | "update" | "detail", departmentId: string) {
  449. dialogVisible.type = type;
  450. dialogVisible.entity = "department";
  451. currentDepartmentId.value = departmentId;
  452. if (type === "create") {
  453. dialogVisible.title = "添加部门";
  454. } else if (type === "update") {
  455. dialogVisible.title = "编辑部门";
  456. } else {
  457. dialogVisible.title = "部门详情";
  458. }
  459. dialogVisible.visible = true;
  460. }
  461. async function handleCloseDialog() {
  462. dialogVisible.visible = false;
  463. }
  464. function handleSubmit() {
  465. formRef.value?.submitForm();
  466. }
  467. function handleResetForm() {
  468. formRef.value?.resetForm();
  469. }
  470. function handleSaveAndAddNext() {
  471. formRef.value?.handleSaveAndAddNext();
  472. }
  473. function handleDeptSubmit(isContinue = false) {
  474. deptFormRef.value?.submitForm(isContinue);
  475. }
  476. function handleFormSuccess() {
  477. dialogVisible.visible = false;
  478. refreshList();
  479. }
  480. function handleDeptFormSuccess() {
  481. dialogVisible.visible = false;
  482. refreshDeptList();
  483. }
  484. async function handleDeleteDepartment(departmentId: string, departmentName: string) {
  485. try {
  486. const enterpriseId = currentEnterpriseId.value || enterpriseIdFromUrl.value;
  487. if (!enterpriseId) {
  488. ElMessage.warning("请先选择企业");
  489. return;
  490. }
  491. await ElMessageBox.confirm(
  492. `确定要删除部门「${departmentName}」吗?`,
  493. "删除部门",
  494. {
  495. confirmButtonText: "确定",
  496. cancelButtonText: "取消",
  497. type: "warning"
  498. }
  499. );
  500. const res = await DepartmentAPI.deleteDepartment(departmentId, enterpriseId);
  501. if (res.data.code === 200) {
  502. ElMessage.success("删除部门成功");
  503. refreshDeptList();
  504. } else {
  505. ElMessage.error(res.data.message || "删除部门失败");
  506. }
  507. } catch (error: any) {
  508. if (error.message !== "cancel") {
  509. console.error("删除部门失败:", error);
  510. ElMessage.error("删除部门失败");
  511. }
  512. }
  513. }
  514. // 获取员工签约激活链接
  515. async function handleGetInviteLink(row: any) {
  516. try {
  517. const enterpriseId = row.enterprise_id || currentEnterpriseId.value || enterpriseIdFromUrl.value;
  518. if (!enterpriseId) {
  519. ElMessage.warning("请先选择企业");
  520. return;
  521. }
  522. const res = await EmployeeAPI.inviteQuery({
  523. enterprise_id: enterpriseId,
  524. employee_id: row.employee_id,
  525. create_share_code: "Y", // 默认生成签约吱口令
  526. });
  527. if (res.data.data) {
  528. inviteDialogVisible.data = res.data.data;
  529. inviteDialogVisible.visible = true;
  530. }
  531. } catch (error) {
  532. ElMessage.error("获取签约链接失败");
  533. }
  534. }
  535. // 复制链接
  536. async function copyInviteLink(text: string) {
  537. try {
  538. await navigator.clipboard.writeText(text);
  539. ElMessage.success("链接已复制到剪贴板");
  540. } catch (err) {
  541. ElMessage.error("复制失败,请手动复制");
  542. }
  543. }
  544. </script>
  545. <style scoped lang="scss">
  546. .employee-tabs {
  547. .el-tabs__nav {
  548. background-color: #fff;
  549. }
  550. .el-tabs__content {
  551. padding: 32px;
  552. color: #6b778c;
  553. font-size: 32px;
  554. font-weight: 600;
  555. }
  556. }
  557. .invite-link-container {
  558. .link-item {
  559. display: flex;
  560. align-items: center;
  561. gap: 8px;
  562. .el-link {
  563. flex: 1;
  564. word-break: break-all;
  565. }
  566. }
  567. .qrcode-item {
  568. display: flex;
  569. align-items: flex-start;
  570. gap: 16px;
  571. }
  572. .qrcode-container {
  573. display: flex;
  574. flex-direction: column;
  575. align-items: center;
  576. }
  577. .qrcode {
  578. width: 200px;
  579. height: 200px;
  580. border: 1px solid #e0e0e0;
  581. }
  582. .qrcode-tip {
  583. margin-top: 8px;
  584. font-size: 14px;
  585. color: #666;
  586. }
  587. .qrcode-error {
  588. padding: 20px;
  589. color: #f56c6c;
  590. }
  591. }
  592. </style>