|
|
@@ -28,21 +28,16 @@
|
|
|
</template>
|
|
|
<el-table-column v-if="contentCols.find((col) => col.prop === 'selection')?.show" type="selection"
|
|
|
min-width="55" align="center" />
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_id')?.show" key="employee_id"
|
|
|
- label="员工ID" prop="employee_id" min-width="150" show-overflow-tooltip />
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'alipay_employee_id')?.show"
|
|
|
- key="alipay_employee_id" label="支付宝员工ID" prop="alipay_employee_id" min-width="150"
|
|
|
- show-overflow-tooltip />
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'name')?.show" key="name" label="员工姓名"
|
|
|
- prop="name" min-width="120" show-overflow-tooltip />
|
|
|
+ <!-- <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_id')?.show" key="employee_id"
|
|
|
+ label="员工ID" prop="employee_id" min-width="150" show-overflow-tooltip /> -->
|
|
|
+ <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_name')?.show" key="employee_name" label="员工姓名"
|
|
|
+ prop="employee_name" min-width="120" show-overflow-tooltip />
|
|
|
<el-table-column v-if="contentCols.find((col) => col.prop === 'employee_no')?.show" key="employee_no"
|
|
|
label="员工工号" prop="employee_no" min-width="120" show-overflow-tooltip />
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'mobile')?.show" key="mobile" label="手机号"
|
|
|
- prop="mobile" min-width="120" />
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'id_card')?.show" key="id_card"
|
|
|
- label="身份证号" prop="id_card" min-width="180" show-overflow-tooltip />
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'email')?.show" key="email" label="邮箱"
|
|
|
- prop="email" min-width="150" show-overflow-tooltip />
|
|
|
+ <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_mobile')?.show" key="employee_mobile" label="手机号"
|
|
|
+ prop="employee_mobile" min-width="120" />
|
|
|
+ <el-table-column v-if="contentCols.find((col) => col.prop === 'employee_email')?.show" key="employee_email" label="邮箱"
|
|
|
+ prop="employee_email" min-width="150" show-overflow-tooltip />
|
|
|
<el-table-column v-if="contentCols.find((col) => col.prop === 'status')?.show" key="status" label="激活状态"
|
|
|
prop="status" min-width="100">
|
|
|
<template #default="scope">
|
|
|
@@ -51,14 +46,6 @@
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column v-if="contentCols.find((col) => col.prop === 'role')?.show" key="role" label="角色"
|
|
|
- prop="role" min-width="100">
|
|
|
- <template #default="scope">
|
|
|
- <el-tag type="info">
|
|
|
- {{ scope.row.role_name || '普通员工' }}
|
|
|
- </el-tag>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
<el-table-column v-if="contentCols.find((col) => col.prop === 'created_time')?.show" key="created_time"
|
|
|
label="创建时间" prop="created_time" min-width="160" sortable />
|
|
|
<el-table-column v-if="contentCols.find((col) => col.prop === 'operation')?.show" fixed="right"
|
|
|
@@ -72,6 +59,10 @@
|
|
|
@click="handleOpenDialog('update', scope.row.employee_id)">
|
|
|
编辑
|
|
|
</el-button>
|
|
|
+ <el-button v-hasPerm="['module_payment:employee:invite']" type="success" size="small" link
|
|
|
+ @click="handleGetInviteLink(scope.row)">
|
|
|
+ 签约链接
|
|
|
+ </el-button>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
</el-table>
|
|
|
@@ -154,7 +145,7 @@
|
|
|
<EnhancedDialog v-model="dialogVisible.visible" :title="dialogVisible.title" @close="handleCloseDialog">
|
|
|
<template v-if="dialogVisible.type === 'detail'">
|
|
|
<template v-if="dialogVisible.entity === 'employee'">
|
|
|
- <EmployeeDetail :employee-id="currentEmployeeId" />
|
|
|
+ <EmployeeDetail :employee-id="currentEmployeeId" :enterprise-id="currentEnterpriseId" />
|
|
|
</template>
|
|
|
<template v-else-if="dialogVisible.entity === 'department'">
|
|
|
<DepartmentDetail :department-id="currentDepartmentId" />
|
|
|
@@ -168,7 +159,7 @@
|
|
|
</template>
|
|
|
<template v-else-if="dialogVisible.entity === 'department'">
|
|
|
<DepartmentForm ref="deptFormRef" :type="dialogVisible.type" :department-id="currentDepartmentId"
|
|
|
- :enterprise-id="currentEnterpriseId" @success="handleDeptFormSuccess" />
|
|
|
+ :enterprise-id="currentEnterpriseId || enterpriseIdFromUrl.value" @success="handleDeptFormSuccess" />
|
|
|
</template>
|
|
|
</template>
|
|
|
|
|
|
@@ -200,6 +191,53 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
</EnhancedDialog>
|
|
|
+
|
|
|
+ <!-- 签约链接对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="inviteDialogVisible.visible"
|
|
|
+ :title="inviteDialogVisible.title"
|
|
|
+ width="600px"
|
|
|
+ @close="inviteDialogVisible.data = null"
|
|
|
+ >
|
|
|
+ <div v-if="inviteDialogVisible.data" class="invite-link-container">
|
|
|
+ <el-descriptions :column="1" border>
|
|
|
+ <el-descriptions-item label="邀请链接">
|
|
|
+ <div class="link-item">
|
|
|
+ <el-link type="primary" :href="inviteDialogVisible.data.sign_url" target="_blank">
|
|
|
+ {{ inviteDialogVisible.data.sign_url }}
|
|
|
+ </el-link>
|
|
|
+ <el-button type="text" size="small" @click="copyInviteLink(inviteDialogVisible.data.sign_url)">
|
|
|
+ 复制
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-descriptions-item>
|
|
|
+
|
|
|
+ <!-- <el-descriptions-item label="小程序签约二维码">
|
|
|
+ <div class="qrcode-item">
|
|
|
+ <div v-if="miniAppQrCode" class="qrcode-container">
|
|
|
+ <img :src="miniAppQrCode" alt="小程序签约二维码" class="qrcode" />
|
|
|
+ <p class="qrcode-tip">请使用支付宝扫码</p>
|
|
|
+ </div>
|
|
|
+ <div v-else class="qrcode-error">
|
|
|
+ 二维码生成失败
|
|
|
+ </div>
|
|
|
+ <el-button type="text" size="small" @click="copyInviteLink(inviteDialogVisible.data.mini_app_sign_url)">
|
|
|
+ 复制链接
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-descriptions-item> -->
|
|
|
+
|
|
|
+ <el-descriptions-item v-if="inviteDialogVisible.data.share_code" label="签约吱口令">
|
|
|
+ <div class="link-item">
|
|
|
+ <span>{{ inviteDialogVisible.data.share_code }}</span>
|
|
|
+ <el-button type="text" size="small" @click="copyInviteLink(inviteDialogVisible.data.share_code)">
|
|
|
+ 复制
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </el-descriptions-item>
|
|
|
+ </el-descriptions>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -209,16 +247,14 @@ defineOptions({
|
|
|
inheritAttrs: false,
|
|
|
});
|
|
|
|
|
|
-import { View, Plus } from "@element-plus/icons-vue";
|
|
|
+import { View } from "@element-plus/icons-vue";
|
|
|
import EmployeeAPI, {
|
|
|
EmployeePageQuery,
|
|
|
- EmployeeTable,
|
|
|
STATUS_TAG_TYPE,
|
|
|
STATUS_LABEL,
|
|
|
} from "@/api/module_payment/employee";
|
|
|
import DepartmentAPI, {
|
|
|
DepartmentPageQuery,
|
|
|
- DepartmentTable,
|
|
|
DEPARTMENT_STATUS_TAG_TYPE,
|
|
|
DEPARTMENT_STATUS_LABEL,
|
|
|
} from "@/api/module_payment/department";
|
|
|
@@ -235,8 +271,10 @@ import type { ISearchConfig, IContentConfig } from "@/components/CURD/types";
|
|
|
import { useCrudList } from "@/components/CURD/useCrudList";
|
|
|
import { useLoadingAction } from "@/composables/useLoadingAction";
|
|
|
import { useRoute } from "vue-router";
|
|
|
-import { ref, reactive, onMounted, computed } from "vue";
|
|
|
+import { ref, reactive, computed } from "vue";
|
|
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
+import { useEnterpriseStore } from "@/store/modules/enterprise.store";
|
|
|
+import QRCode from "qrcode";
|
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
@@ -258,13 +296,13 @@ const searchConfig = reactive<ISearchConfig>({
|
|
|
form: { labelWidth: "auto" },
|
|
|
formItems: [
|
|
|
{
|
|
|
- prop: "name",
|
|
|
+ prop: "employee_name",
|
|
|
label: "员工姓名",
|
|
|
type: "input",
|
|
|
attrs: { placeholder: "请输入员工姓名", clearable: true },
|
|
|
},
|
|
|
{
|
|
|
- prop: "mobile",
|
|
|
+ prop: "employee_mobile",
|
|
|
label: "手机号",
|
|
|
type: "input",
|
|
|
attrs: { placeholder: "请输入手机号", clearable: true },
|
|
|
@@ -278,6 +316,30 @@ const searchConfig = reactive<ISearchConfig>({
|
|
|
],
|
|
|
});
|
|
|
|
|
|
+const dialogVisible = reactive({
|
|
|
+ title: "",
|
|
|
+ visible: false,
|
|
|
+ type: "create" as "create" | "update" | "detail",
|
|
|
+ entity: "employee" as "employee" | "department",
|
|
|
+});
|
|
|
+
|
|
|
+const inviteDialogVisible = reactive({
|
|
|
+ visible: false,
|
|
|
+ title: "员工签约激活链接",
|
|
|
+ data: null as any,
|
|
|
+});
|
|
|
+
|
|
|
+const useEnterprise = useEnterpriseStore();
|
|
|
+
|
|
|
+const currentEmployeeId = ref<string>('');
|
|
|
+const currentDepartmentId = ref<string>('');
|
|
|
+const currentEnterpriseId = computed(() => useEnterprise.getCurrentEnterprise?.enterprise_id || "");
|
|
|
+
|
|
|
+// 小程序链接二维码
|
|
|
+const miniAppQrCode = computed(() => {
|
|
|
+ return '';
|
|
|
+});
|
|
|
+
|
|
|
// 部门搜索配置
|
|
|
const deptSearchConfig = reactive<ISearchConfig>({
|
|
|
permPrefix: "module_payment:department",
|
|
|
@@ -340,15 +402,12 @@ const contentCols = reactive<
|
|
|
>([
|
|
|
{ prop: "selection", label: "选择框", show: false },
|
|
|
{ prop: "index", label: "序号", show: true },
|
|
|
- { prop: "name", label: "员工姓名", show: true },
|
|
|
+ { prop: "employee_name", label: "员工姓名", show: true },
|
|
|
{ prop: "employee_no", label: "员工工号", show: true },
|
|
|
{ prop: "employee_id", label: "员工ID", show: true },
|
|
|
- { prop: "alipay_employee_id", label: "支付宝员工ID", show: true },
|
|
|
- { prop: "mobile", label: "手机号", show: true },
|
|
|
- { prop: "id_card", label: "身份证号", show: true },
|
|
|
- { prop: "email", label: "邮箱", show: true },
|
|
|
+ { prop: "employee_mobile", label: "手机号", show: true },
|
|
|
+ { prop: "employee_email", label: "邮箱", show: true },
|
|
|
{ prop: "status", label: "激活状态", show: true },
|
|
|
- { prop: "role", label: "角色", show: true },
|
|
|
{ prop: "created_time", label: "创建时间", show: true },
|
|
|
{ prop: "operation", label: "操作", show: true },
|
|
|
]);
|
|
|
@@ -361,17 +420,13 @@ const contentConfig = reactive<IContentConfig<EmployeePageQuery>>({
|
|
|
toolbar: [],
|
|
|
defaultToolbar: ["refresh", "filter", "import", "export"],
|
|
|
pagination: true,
|
|
|
- initialParams: computed(() => ({
|
|
|
- enterprise_id: enterpriseIdFromUrl.value,
|
|
|
- })) as Record<string, unknown>,
|
|
|
indexAction: async (params) => {
|
|
|
const query: EmployeePageQuery = {
|
|
|
page_no: params.page_no,
|
|
|
page_size: params.page_size,
|
|
|
};
|
|
|
- if (params.enterprise_id) query.enterprise_id = params.enterprise_id;
|
|
|
- if (params.name) query.name = params.name;
|
|
|
- if (params.mobile) query.mobile = params.mobile;
|
|
|
+ if (params.employee_name) query.employee_name = params.employee_name;
|
|
|
+ if (params.employee_mobile) query.employee_mobile = params.employee_mobile;
|
|
|
if (params.employee_no) query.employee_no = params.employee_no;
|
|
|
const res = await EmployeeAPI.listEmployee(query);
|
|
|
return {
|
|
|
@@ -399,33 +454,34 @@ const deptContentConfig = reactive<IContentConfig<DepartmentPageQuery>>({
|
|
|
page_size: params.page_size,
|
|
|
};
|
|
|
if (params.enterprise_id) query.enterprise_id = params.enterprise_id;
|
|
|
- if (params.name) query.name = params.name;
|
|
|
- if (params.code) query.code = params.code;
|
|
|
+ if (params.name) query.department_name = params.name;
|
|
|
+ if (params.code) query.department_code = params.code;
|
|
|
if (params.status) query.status = params.status;
|
|
|
const res = await DepartmentAPI.listDepartment(query);
|
|
|
+ // 转换数据结构以匹配前端表格显示
|
|
|
+ const items = res.data.data?.items.map((item: any) => ({
|
|
|
+ department_id: item.department_id,
|
|
|
+ name: item.department_name,
|
|
|
+ code: item.department_code,
|
|
|
+ parent_id: item.parent_department_id,
|
|
|
+ parent_name: '', // 可以根据parent_id查询上级部门名称
|
|
|
+ leader_employee_name: item.leader_employee_name,
|
|
|
+ sort_order: item.sort_order,
|
|
|
+ status: item.status,
|
|
|
+ created_time: item.created_time,
|
|
|
+ updated_time: item.updated_time
|
|
|
+ })) || [];
|
|
|
return {
|
|
|
- list: res.data.data?.items || [],
|
|
|
+ list: items,
|
|
|
total: res.data.data?.total || 0,
|
|
|
};
|
|
|
},
|
|
|
});
|
|
|
|
|
|
-const dialogVisible = reactive({
|
|
|
- title: "",
|
|
|
- visible: false,
|
|
|
- type: "create" as "create" | "update" | "detail",
|
|
|
- entity: "employee" as "employee" | "department",
|
|
|
-});
|
|
|
-
|
|
|
-const currentEmployeeId = ref<string>();
|
|
|
-const currentDepartmentId = ref<string>();
|
|
|
-const currentEnterpriseId = ref<string>();
|
|
|
-
|
|
|
-function handleOpenDialog(type: "create" | "update" | "detail", employeeId?: string) {
|
|
|
+function handleOpenDialog(type: "create" | "update" | "detail", employeeId: string) {
|
|
|
dialogVisible.type = type;
|
|
|
dialogVisible.entity = "employee";
|
|
|
currentEmployeeId.value = employeeId;
|
|
|
- currentEnterpriseId.value = enterpriseIdFromUrl.value;
|
|
|
if (type === "create") {
|
|
|
dialogVisible.title = "添加员工";
|
|
|
} else if (type === "update") {
|
|
|
@@ -436,11 +492,10 @@ function handleOpenDialog(type: "create" | "update" | "detail", employeeId?: str
|
|
|
dialogVisible.visible = true;
|
|
|
}
|
|
|
|
|
|
-function handleOpenDeptDialog(type: "create" | "update" | "detail", departmentId?: string) {
|
|
|
+function handleOpenDeptDialog(type: "create" | "update" | "detail", departmentId: string) {
|
|
|
dialogVisible.type = type;
|
|
|
dialogVisible.entity = "department";
|
|
|
currentDepartmentId.value = departmentId;
|
|
|
- currentEnterpriseId.value = enterpriseIdFromUrl.value;
|
|
|
if (type === "create") {
|
|
|
dialogVisible.title = "添加部门";
|
|
|
} else if (type === "update") {
|
|
|
@@ -483,6 +538,12 @@ function handleDeptFormSuccess() {
|
|
|
|
|
|
async function handleDeleteDepartment(departmentId: string, departmentName: string) {
|
|
|
try {
|
|
|
+ const enterpriseId = currentEnterpriseId.value || enterpriseIdFromUrl.value;
|
|
|
+ if (!enterpriseId) {
|
|
|
+ ElMessage.warning("请先选择企业");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
await ElMessageBox.confirm(
|
|
|
`确定要删除部门「${departmentName}」吗?`,
|
|
|
"删除部门",
|
|
|
@@ -493,7 +554,7 @@ async function handleDeleteDepartment(departmentId: string, departmentName: stri
|
|
|
}
|
|
|
);
|
|
|
|
|
|
- const res = await DepartmentAPI.deleteDepartment(departmentId);
|
|
|
+ const res = await DepartmentAPI.deleteDepartment(departmentId, enterpriseId);
|
|
|
if (res.data.code === 200) {
|
|
|
ElMessage.success("删除部门成功");
|
|
|
refreshDeptList();
|
|
|
@@ -507,6 +568,40 @@ async function handleDeleteDepartment(departmentId: string, departmentName: stri
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// 获取员工签约激活链接
|
|
|
+async function handleGetInviteLink(row: any) {
|
|
|
+ try {
|
|
|
+ const enterpriseId = currentEnterpriseId.value || enterpriseIdFromUrl.value;
|
|
|
+ if (!enterpriseId) {
|
|
|
+ ElMessage.warning("请先选择企业");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await EmployeeAPI.inviteQuery({
|
|
|
+ enterprise_id: enterpriseId,
|
|
|
+ employee_id: row.employee_id,
|
|
|
+ create_share_code: "Y", // 默认生成签约吱口令
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.data.data) {
|
|
|
+ inviteDialogVisible.data = res.data.data;
|
|
|
+ inviteDialogVisible.visible = true;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error("获取签约链接失败");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 复制链接
|
|
|
+async function copyInviteLink(text: string) {
|
|
|
+ try {
|
|
|
+ await navigator.clipboard.writeText(text);
|
|
|
+ ElMessage.success("链接已复制到剪贴板");
|
|
|
+ } catch (err) {
|
|
|
+ ElMessage.error("复制失败,请手动复制");
|
|
|
+ }
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
@@ -522,4 +617,46 @@ async function handleDeleteDepartment(departmentId: string, departmentName: stri
|
|
|
font-weight: 600;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.invite-link-container {
|
|
|
+ .link-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+
|
|
|
+ .el-link {
|
|
|
+ flex: 1;
|
|
|
+ word-break: break-all;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .qrcode-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .qrcode-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .qrcode {
|
|
|
+ width: 200px;
|
|
|
+ height: 200px;
|
|
|
+ border: 1px solid #e0e0e0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .qrcode-tip {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+
|
|
|
+ .qrcode-error {
|
|
|
+ padding: 20px;
|
|
|
+ color: #f56c6c;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|