|
|
@@ -23,12 +23,16 @@
|
|
|
<el-table :data="rows" v-loading="loading" border stripe style="width: 100%" max-height="calc(100vh - 260px)">
|
|
|
<el-table-column prop="employee" label="员工编码" width="130" show-overflow-tooltip />
|
|
|
<el-table-column prop="name" label="姓名" width="100" show-overflow-tooltip />
|
|
|
- <el-table-column prop="sex" label="性别" width="70" show-overflow-tooltip />
|
|
|
+ <el-table-column label="性别" width="70" show-overflow-tooltip>
|
|
|
+ <template #default="{ row }">{{ sexLabel(row.sex) }}</template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="phone" label="电话" width="130" show-overflow-tooltip />
|
|
|
<el-table-column prop="department" label="部门" width="110" show-overflow-tooltip />
|
|
|
<el-table-column prop="departDescr" label="部门说明" min-width="130" show-overflow-tooltip />
|
|
|
<el-table-column prop="jobTitleDisplay" label="岗位" width="120" show-overflow-tooltip />
|
|
|
- <el-table-column prop="employmentStatus" label="在职状态" width="100" show-overflow-tooltip />
|
|
|
+ <el-table-column label="在职状态" width="100" show-overflow-tooltip>
|
|
|
+ <template #default="{ row }">{{ employmentLabel(row.employmentStatus) }}</template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column prop="dateEmployed" label="入职日期" width="110" show-overflow-tooltip />
|
|
|
<el-table-column label="启用" width="80" align="center">
|
|
|
<template #default="{ row }">
|
|
|
@@ -49,53 +53,84 @@
|
|
|
@current-change="loadList" @size-change="loadList" />
|
|
|
</div>
|
|
|
|
|
|
- <el-dialog v-model="dialogVisible" :title="dialogTitle" width="720px" destroy-on-close @closed="resetForm">
|
|
|
- <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
|
|
+ <el-dialog v-model="dialogVisible" :title="dialogTitle" width="900px" destroy-on-close @closed="resetForm">
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="90px">
|
|
|
<el-row :gutter="16">
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item v-if="false" label="公司" prop="companyRefId">
|
|
|
+ <el-col v-if="false" :span="12">
|
|
|
+ <el-form-item label="公司" prop="companyRefId">
|
|
|
<el-select v-model="form.companyRefId" clearable filterable placeholder="请选择公司" style="width: 100%">
|
|
|
<el-option v-for="item in companyOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item v-if="false" label="工厂" prop="factoryRefId">
|
|
|
+ <el-col v-if="false" :span="12">
|
|
|
+ <el-form-item label="工厂" prop="factoryRefId">
|
|
|
<el-select v-model="form.factoryRefId" clearable filterable placeholder="请选择工厂" style="width: 100%" :disabled="!form.companyRefId">
|
|
|
<el-option v-for="item in formFactoryOptions" :key="item.id" :label="item.name || item.code || `${item.id}`" :value="item.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="员工编码" prop="employee"><el-input v-model="form.employee" :disabled="!!editingId" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="姓名"><el-input v-model="form.name" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="性别"><el-input v-model="form.sex" placeholder="M/F" /></el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="电话"><el-input v-model="form.phone" /></el-form-item>
|
|
|
+ <el-col :span="8"><el-form-item label="员工编码" prop="employee"><el-input v-model="form.employee" :disabled="!!editingId" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="姓名"><el-input v-model="form.name" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="性别">
|
|
|
+ <el-select v-model="form.sex" clearable placeholder="请选择" style="width: 100%">
|
|
|
+ <el-option v-for="o in SEX_OPTIONS" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="部门">
|
|
|
+ <el-select v-model="form.department" clearable filterable placeholder="请选择部门" style="width: 100%">
|
|
|
+ <el-option v-for="o in deptOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="部门"><el-input v-model="form.department" /></el-form-item>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="岗位">
|
|
|
+ <el-select v-model="form.jobTitle" clearable filterable placeholder="请选择岗位" style="width: 100%">
|
|
|
+ <el-option v-for="o in jobTitleOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="岗位"><el-input v-model="form.jobTitle" /></el-form-item>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="在职状态">
|
|
|
+ <el-select v-model="form.employmentStatus" clearable placeholder="请选择" style="width: 100%">
|
|
|
+ <el-option v-for="o in EMPLOYMENT_OPTIONS" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="在职状态"><el-input v-model="form.employmentStatus" /></el-form-item>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="默认生产线">
|
|
|
+ <el-select v-model="form.defaultWorkLocation" clearable filterable placeholder="请选择生产线" style="width: 100%">
|
|
|
+ <el-option v-for="o in lineOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col v-if="false" :span="12">
|
|
|
- <el-form-item label="域编码"><el-input v-model="form.domainCode" /></el-form-item>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="工作中心">
|
|
|
+ <el-select v-model="form.workCtr" clearable filterable placeholder="请选择工作中心" style="width: 100%">
|
|
|
+ <el-option v-for="o in workCtrOptions" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="启用"><el-switch v-model="form.isActive" /></el-form-item>
|
|
|
+ <el-col :span="8">
|
|
|
+ <el-form-item label="婚姻状态">
|
|
|
+ <el-select v-model="form.maritalStatus" clearable placeholder="请选择" style="width: 100%">
|
|
|
+ <el-option v-for="o in MARITAL_OPTIONS" :key="o.value" :label="o.label" :value="o.value" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
</el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="电话"><el-input v-model="form.phone" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="业务电话"><el-input v-model="form.businessPhone" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="卡ID"><el-input v-model="form.carId" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="城市"><el-input v-model="form.city" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="国家"><el-input v-model="form.country" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="出生日期"><el-date-picker v-model="form.birthDate" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="入职日期"><el-date-picker v-model="form.dateEmployed" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="离职日期"><el-date-picker v-model="form.dateTerminated" type="date" value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 100%" /></el-form-item></el-col>
|
|
|
+ <el-col :span="8"><el-form-item label="启用"><el-switch v-model="form.isActive" /></el-form-item></el-col>
|
|
|
</el-row>
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
@@ -111,9 +146,22 @@ import { computed, onMounted, reactive, ref, watch } from 'vue';
|
|
|
import { useRoute } from 'vue-router';
|
|
|
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
|
|
|
import AidopDemoShell from '../../components/AidopDemoShell.vue';
|
|
|
-import { s0EmployeesApi, type S0EmployeeRow, type S0EmployeeUpsert } from '../api/s0WarehouseApi';
|
|
|
+import { s0EmployeesApi, s0DepartmentsApi, type S0EmployeeRow, type S0EmployeeUpsert, type S0JobTitleOption } from '../api/s0WarehouseApi';
|
|
|
+import { s0MfgProductionLinesApi, s0MfgWorkCentersApi } from '../api/s0ManufacturingApi';
|
|
|
import { loadOrgList, type OrgOption } from '../api/s0SalesApi';
|
|
|
|
|
|
+// 字典口径(前端固定 0/1):性别 0女1男、在职 0在职1离职、婚姻 0未婚1已婚
|
|
|
+const SEX_OPTIONS = [{ value: '0', label: '女' }, { value: '1', label: '男' }];
|
|
|
+const EMPLOYMENT_OPTIONS = [{ value: '0', label: '在职' }, { value: '1', label: '离职' }];
|
|
|
+const MARITAL_OPTIONS = [{ value: '0', label: '未婚' }, { value: '1', label: '已婚' }];
|
|
|
+function sexLabel(v?: string | null): string { return SEX_OPTIONS.find((o) => o.value === v)?.label ?? (v ?? ''); }
|
|
|
+function employmentLabel(v?: string | null): string { return EMPLOYMENT_OPTIONS.find((o) => o.value === v)?.label ?? (v ?? ''); }
|
|
|
+
|
|
|
+interface Option { value: string; label: string }
|
|
|
+interface DeptLike { department?: string | null; descr?: string | null; domainCode?: string | null }
|
|
|
+interface LineLike { line?: string | null; describe?: string | null }
|
|
|
+interface WorkCtrLike { workCtr?: string | null; descr?: string | null }
|
|
|
+
|
|
|
const route = useRoute();
|
|
|
const pageTitle = computed(() => (route.meta?.title as string) || '雇员列表');
|
|
|
|
|
|
@@ -127,7 +175,16 @@ const editingId = ref<number | null>(null);
|
|
|
const saving = ref(false);
|
|
|
const formRef = ref<FormInstance>();
|
|
|
|
|
|
-const form = reactive<S0EmployeeUpsert>({ companyRefId: undefined, factoryRefId: undefined, domainCode: '', employee: '', name: '', sex: '', phone: '', email: '', department: '', jobTitle: '', employmentStatus: '', isActive: true });
|
|
|
+function emptyForm(): S0EmployeeUpsert {
|
|
|
+ return { companyRefId: undefined, factoryRefId: undefined, domainCode: '', employee: '', name: '', sex: '', phone: '', businessPhone: '', email: '', birthDate: null, department: '', dateEmployed: null, employmentStatus: '', maritalStatus: '', jobTitle: '', dateTerminated: null, workCtr: '', carId: '', defaultWorkLocation: '', city: '', country: '', isActive: true };
|
|
|
+}
|
|
|
+const form = reactive<S0EmployeeUpsert>(emptyForm());
|
|
|
+
|
|
|
+// 下拉数据源(真实主数据)
|
|
|
+const deptOptions = ref<Option[]>([]);
|
|
|
+const lineOptions = ref<Option[]>([]);
|
|
|
+const workCtrOptions = ref<Option[]>([]);
|
|
|
+const jobTitleOptions = ref<Option[]>([]);
|
|
|
|
|
|
// 单甲方私有云口径:公司/工厂不在前端启用,统一注入全局默认组织(不依赖登录账号 tenant_id)
|
|
|
const DEFAULT_COMPANY_REF_ID = '1329900200001';
|
|
|
@@ -159,6 +216,12 @@ watch(
|
|
|
},
|
|
|
);
|
|
|
|
|
|
+// 日期字段回显归一:后端返回 "YYYY-MM-DD HH:mm:ss",date-picker value-format 为 YYYY-MM-DD,取日期段。
|
|
|
+function toDate(v?: string | null): string | null {
|
|
|
+ if (!v) return null;
|
|
|
+ return v.length >= 10 ? v.slice(0, 10) : v;
|
|
|
+}
|
|
|
+
|
|
|
async function loadList() {
|
|
|
loading.value = true;
|
|
|
try {
|
|
|
@@ -170,13 +233,20 @@ async function loadList() {
|
|
|
function resetQuery() { Object.assign(query, { keyword: '', domainCode: '', department: '', isActive: undefined, page: 1 }); void loadList(); }
|
|
|
function resetForm() {
|
|
|
editingId.value = null;
|
|
|
- Object.assign(form, { companyRefId: undefined, factoryRefId: undefined, domainCode: '', employee: '', name: '', sex: '', phone: '', email: '', department: '', jobTitle: '', employmentStatus: '', isActive: true });
|
|
|
+ Object.assign(form, emptyForm());
|
|
|
formRef.value?.clearValidate();
|
|
|
}
|
|
|
function openCreate() { resetForm(); dialogTitle.value = '新增雇员'; dialogVisible.value = true; }
|
|
|
function openEdit(row: S0EmployeeRow) {
|
|
|
resetForm(); editingId.value = row.id; dialogTitle.value = `编辑雇员 ${row.employee}`;
|
|
|
- Object.assign(form, { companyRefId: row.companyRefId, factoryRefId: row.factoryRefId, domainCode: row.domainCode ?? '', employee: row.employee, name: row.name ?? '', sex: row.sex ?? '', phone: row.phone ?? '', email: row.email ?? '', department: row.department ?? '', jobTitle: row.jobTitle ?? '', employmentStatus: row.employmentStatus ?? '', isActive: row.isActive });
|
|
|
+ Object.assign(form, {
|
|
|
+ companyRefId: row.companyRefId, factoryRefId: row.factoryRefId, domainCode: row.domainCode ?? '',
|
|
|
+ employee: row.employee, name: row.name ?? '', sex: row.sex ?? '', phone: row.phone ?? '', businessPhone: row.businessPhone ?? '',
|
|
|
+ email: row.email ?? '', birthDate: toDate(row.birthDate), department: row.department ?? '', dateEmployed: toDate(row.dateEmployed),
|
|
|
+ employmentStatus: row.employmentStatus ?? '', maritalStatus: row.maritalStatus ?? '', jobTitle: row.jobTitle ?? '',
|
|
|
+ dateTerminated: toDate(row.dateTerminated), workCtr: row.workCtr ?? '', carId: row.carId ?? '',
|
|
|
+ defaultWorkLocation: row.defaultWorkLocation ?? '', city: row.city ?? '', country: row.country ?? '', isActive: row.isActive,
|
|
|
+ });
|
|
|
dialogVisible.value = true;
|
|
|
}
|
|
|
async function submitForm() {
|
|
|
@@ -193,13 +263,47 @@ function onDelete(row: S0EmployeeRow) {
|
|
|
ElMessageBox.confirm(`确定删除雇员「${row.name || row.employee}」?`, '确认', { type: 'warning' })
|
|
|
.then(async () => { await s0EmployeesApi.delete(row.id); ElMessage.success('已删除'); await loadList(); }).catch(() => {});
|
|
|
}
|
|
|
+
|
|
|
async function loadOrgOptions() {
|
|
|
const [companies, factories] = await Promise.all([loadOrgList('201'), loadOrgList('501')]);
|
|
|
companyOptions.value = companies.filter((item) => item.id && item.id !== '0');
|
|
|
factoryOptions.value = factories.filter((item) => item.id && item.id !== '0');
|
|
|
}
|
|
|
|
|
|
-onMounted(() => { void loadList(); void loadOrgOptions(); });
|
|
|
+// 加载真实下拉源:部门 / 生产线 / 工作中心 / 岗位
|
|
|
+async function loadDropdownSources() {
|
|
|
+ const bigPage = { page: 1, pageSize: 500 };
|
|
|
+ // 工作中心接口按工厂域过滤(Domain 必填),从部门主数据取当前租户实际工作域,避免硬编码。
|
|
|
+ let workingDomain = '';
|
|
|
+ try {
|
|
|
+ const dept = await s0DepartmentsApi.list(bigPage);
|
|
|
+ const deptRows = dept.list as DeptLike[];
|
|
|
+ deptOptions.value = deptRows
|
|
|
+ .filter((d) => !!d.department)
|
|
|
+ .map((d) => ({ value: d.department as string, label: d.descr ? `${d.department} ${d.descr}` : (d.department as string) }));
|
|
|
+ workingDomain = deptRows.map((d) => d.domainCode ?? '').find((dc) => !!dc) ?? '';
|
|
|
+ } catch { deptOptions.value = []; }
|
|
|
+ try {
|
|
|
+ const lines = await s0MfgProductionLinesApi.list(bigPage);
|
|
|
+ lineOptions.value = (lines.list as LineLike[])
|
|
|
+ .filter((l) => !!l.line)
|
|
|
+ .map((l) => ({ value: l.line as string, label: l.describe ? `${l.line} ${l.describe}` : (l.line as string) }));
|
|
|
+ } catch { lineOptions.value = []; }
|
|
|
+ if (workingDomain) {
|
|
|
+ try {
|
|
|
+ const wc = await s0MfgWorkCentersApi.list({ ...bigPage, domain: workingDomain });
|
|
|
+ workCtrOptions.value = (wc.list as WorkCtrLike[])
|
|
|
+ .filter((w) => !!w.workCtr)
|
|
|
+ .map((w) => ({ value: w.workCtr as string, label: w.descr ? `${w.workCtr} ${w.descr}` : (w.workCtr as string) }));
|
|
|
+ } catch { workCtrOptions.value = []; }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ const jobs: S0JobTitleOption[] = await s0EmployeesApi.jobTitleOptions();
|
|
|
+ jobTitleOptions.value = jobs.map((j) => ({ value: j.value, label: j.label || j.value }));
|
|
|
+ } catch { jobTitleOptions.value = []; }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => { void loadList(); void loadOrgOptions(); void loadDropdownSources(); });
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|