|
@@ -134,7 +134,8 @@
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :xs="24" :sm="12"><el-form-item label="岗位性质"><el-select v-model="form.employmentType" filterable
|
|
<el-col :xs="24" :sm="12"><el-form-item label="岗位性质"><el-select v-model="form.employmentType" filterable
|
|
|
- clearable class="full-width" :placeholder="form.positionId ? '请选择岗位性质' : '请先选择岗位'">
|
|
|
|
|
|
|
+ clearable class="full-width" :placeholder="form.positionId ? '请选择岗位性质' : '请先选择岗位'"
|
|
|
|
|
+ @change="syncEmploymentTypeName">
|
|
|
<el-option v-for="item in employmentOptions" :key="item.key || item.value" :label="item.label"
|
|
<el-option v-for="item in employmentOptions" :key="item.key || item.value" :label="item.label"
|
|
|
:value="item.value" />
|
|
:value="item.value" />
|
|
|
</el-select></el-form-item></el-col>
|
|
</el-select></el-form-item></el-col>
|
|
@@ -660,7 +661,7 @@ const emptyForm = () => ({
|
|
|
// 岗位序列(部门 → 序列 → 岗位 → 性质 → 层级,与办理入职一致)
|
|
// 岗位序列(部门 → 序列 → 岗位 → 性质 → 层级,与办理入职一致)
|
|
|
positionSequenceId: '', positionSequence: '', positionSequenceName: '',
|
|
positionSequenceId: '', positionSequence: '', positionSequenceName: '',
|
|
|
positionType: '', level: '', staffingLevel: '', dutyLevel: '', manager: '', managerId: null,
|
|
positionType: '', level: '', staffingLevel: '', dutyLevel: '', manager: '', managerId: null,
|
|
|
- employmentType: '', status: '全职', hireDate: '', regularDate: '', account: '', enabled: true,
|
|
|
|
|
|
|
+ employmentType: '', employmentTypeName: '', status: '全职', hireDate: '', regularDate: '', account: '', enabled: true,
|
|
|
keyProcess: '',
|
|
keyProcess: '',
|
|
|
phone: '', email: '', wechat: '', workAddress: '', currentAddress: '', registeredAddress: '', emergencyContact: '', emergencyRelation: '', emergencyPhone: '', familyMembers: [],
|
|
phone: '', email: '', wechat: '', workAddress: '', currentAddress: '', registeredAddress: '', emergencyContact: '', emergencyRelation: '', emergencyPhone: '', familyMembers: [],
|
|
|
education: '本科', school: '', major: '', graduationDate: '',
|
|
education: '本科', school: '', major: '', graduationDate: '',
|
|
@@ -871,12 +872,21 @@ export default {
|
|
|
avatarStyle() { const tones = ['#1890ff', '#13a471', '#7c5ce7', '#d08716', '#d25567']; const code = [...(this.form.name || '新')].reduce((sum, char) => sum + char.charCodeAt(0), 0); return { '--avatar-color': tones[code % tones.length] }; },
|
|
avatarStyle() { const tones = ['#1890ff', '#13a471', '#7c5ce7', '#d08716', '#d25567']; const code = [...(this.form.name || '新')].reduce((sum, char) => sum + char.charCodeAt(0), 0); return { '--avatar-color': tones[code % tones.length] }; },
|
|
|
currentSectionLabel() { return this.sections.find((item) => item.name === this.activeTab)?.label || ''; },
|
|
currentSectionLabel() { return this.sections.find((item) => item.name === this.activeTab)?.label || ''; },
|
|
|
// 所属机构:只取登录缓存所属机构(sessionStorage.loginChangeGroupVOList);
|
|
// 所属机构:只取登录缓存所属机构(sessionStorage.loginChangeGroupVOList);
|
|
|
- // 编辑老数据时原机构不在缓存里,则补一条兜底选项,避免下拉只显示 ID
|
|
|
|
|
|
|
+ // 登录缓存缺失时(兜底选项只有 id 没有名称,会显示成 "1"),回落到组织树里的
|
|
|
|
|
+ // 集团/公司节点(type 10/20),保证下拉可读、可选(如「中赢合力」);
|
|
|
|
|
+ // 编辑老数据时原机构不在选项里,则补一条兜底选项,避免下拉只显示 ID
|
|
|
legalEntities() {
|
|
legalEntities() {
|
|
|
- const list = getOrgOptions().map((item) => ({
|
|
|
|
|
|
|
+ let list = getOrgOptions().map((item) => ({
|
|
|
id: String(item.id),
|
|
id: String(item.id),
|
|
|
name: item.name
|
|
name: item.name
|
|
|
}));
|
|
}));
|
|
|
|
|
+ if (!list.some((item) => item.name)) {
|
|
|
|
|
+ const tree = this.organizationTree.length ? this.organizationTree : this.organizations;
|
|
|
|
|
+ const companies = flattenOrganizationTree(tree || [])
|
|
|
|
|
+ .filter((item) => ['10', '20'].includes(String(item.type)))
|
|
|
|
|
+ .map((item) => ({ id: String(item.id), name: item.name, type: item.type }));
|
|
|
|
|
+ if (companies.length) list = companies;
|
|
|
|
|
+ }
|
|
|
const currentId = this.form.groupId != null && this.form.groupId !== '' ? String(this.form.groupId) : '';
|
|
const currentId = this.form.groupId != null && this.form.groupId !== '' ? String(this.form.groupId) : '';
|
|
|
if (currentId && !list.some((item) => String(item.id) === currentId)) {
|
|
if (currentId && !list.some((item) => String(item.id) === currentId)) {
|
|
|
const tree = this.organizationTree.length ? this.organizationTree : this.organizations;
|
|
const tree = this.organizationTree.length ? this.organizationTree : this.organizations;
|
|
@@ -992,26 +1002,51 @@ export default {
|
|
|
visible(value) { if (value) this.loadForm(); }
|
|
visible(value) { if (value) this.loadForm(); }
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
- /** 员工状态下拉选项。
|
|
|
|
|
- * 以 EMPLOYEE_STATUS(中文 → 后端数字状态码,src/api/organization/index.js)为唯一映射真相源:
|
|
|
|
|
- * - 下拉 value 直接取中文 label,与「回显写中文 / 提交用 EMPLOYEE_STATUS[中文] 转数字」口径一致;
|
|
|
|
|
- * - 字典 employee_status 仅用于提供并排序中文 label,过滤掉表里没有的项,避免选了却提交成默认值;
|
|
|
|
|
- * - 字典为空或不含标准项时,用 EMPLOYEE_STATUS 的全部键兜底,保证一定能选。 */
|
|
|
|
|
|
|
+ /** 员工状态下拉选项:接口字典 hr_user_status(label=中文名,value=状态编码)。
|
|
|
|
|
+ * 下拉 value 用字典编码,回显按状态码匹配、提交直接传编码;
|
|
|
|
|
+ * 字典为空或加载失败时,用 EMPLOYEE_STATUS(中文→数字码)兜底,保证一定能选。 */
|
|
|
async loadStatusOptions() {
|
|
async loadStatusOptions() {
|
|
|
- const items = await getDictByCode('employee_status');
|
|
|
|
|
- const dictLabels = (Array.isArray(items) ? items : [])
|
|
|
|
|
- .map((item) => String(item.label ?? item.name ?? '').trim())
|
|
|
|
|
- .filter(Boolean)
|
|
|
|
|
- .filter((label) => Object.prototype.hasOwnProperty.call(EMPLOYEE_STATUS, label));
|
|
|
|
|
- const labels = dictLabels.length ? dictLabels : Object.keys(EMPLOYEE_STATUS);
|
|
|
|
|
- this.statusOptions = labels.map((label) => ({ label, value: label }));
|
|
|
|
|
|
|
+ const fallback = Object.entries(EMPLOYEE_STATUS).map(([label, code]) => ({ label, value: String(code) }));
|
|
|
|
|
+ try {
|
|
|
|
|
+ const items = await getDictByCode('hr_user_status');
|
|
|
|
|
+ const options = (Array.isArray(items) ? items : [])
|
|
|
|
|
+ .map((item) => {
|
|
|
|
|
+ const label = String(item.label ?? item.name ?? '').trim();
|
|
|
|
|
+ const value = item.value ?? item.id ?? item.key;
|
|
|
|
|
+ if (!label || value == null || value === '') return null;
|
|
|
|
|
+ return { label, value: String(value) };
|
|
|
|
|
+ })
|
|
|
|
|
+ .filter(Boolean);
|
|
|
|
|
+ this.statusOptions = options.length ? options : fallback;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ this.statusOptions = fallback;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 字典晚于表单加载时,把已回填的中文/旧值重新对齐成字典 value
|
|
|
|
|
+ if (this.form.status) {
|
|
|
|
|
+ const hit = this.statusOptions.find(
|
|
|
|
|
+ (opt) => String(opt.value) === String(this.form.status) || opt.label === this.form.status,
|
|
|
|
|
+ );
|
|
|
|
|
+ if (hit) this.form.status = hit.value;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ /** 回显员工状态:优先用后端状态码匹配字典 value,其次按中文 label 匹配 */
|
|
|
|
|
+ resolveStatusForForm(source) {
|
|
|
|
|
+ const code = source.statusCode ?? source.raw?.status;
|
|
|
|
|
+ const byCode = code != null && code !== ''
|
|
|
|
|
+ ? this.statusOptions.find((opt) => String(opt.value) === String(code))
|
|
|
|
|
+ : null;
|
|
|
|
|
+ if (byCode) return byCode.value;
|
|
|
|
|
+ const byLabel = this.statusOptions.find(
|
|
|
|
|
+ (opt) => opt.label === source.formStatus || opt.label === source.status,
|
|
|
|
|
+ );
|
|
|
|
|
+ if (byLabel) return byLabel.value;
|
|
|
|
|
+ return this.statusOptions.length ? this.statusOptions[0].value : (source.formStatus || '');
|
|
|
},
|
|
},
|
|
|
loadForm() {
|
|
loadForm() {
|
|
|
this._skipFormValidate = true;
|
|
this._skipFormValidate = true;
|
|
|
this.activeTab = 'base';
|
|
this.activeTab = 'base';
|
|
|
const source = this.employee ? JSON.parse(JSON.stringify(this.employee)) : {};
|
|
const source = this.employee ? JSON.parse(JSON.stringify(this.employee)) : {};
|
|
|
const empty = emptyForm();
|
|
const empty = emptyForm();
|
|
|
- const statusMap = { active: '全职', probation: '试用', inactive: '离职', disabled: '离职' };
|
|
|
|
|
this.form = {
|
|
this.form = {
|
|
|
...empty, ...source,
|
|
...empty, ...source,
|
|
|
groupId: source.groupId != null && source.groupId !== ''
|
|
groupId: source.groupId != null && source.groupId !== ''
|
|
@@ -1019,7 +1054,7 @@ export default {
|
|
|
: (source.legalEntityId != null && source.legalEntityId !== '' ? String(source.legalEntityId) : null),
|
|
: (source.legalEntityId != null && source.legalEntityId !== '' ? String(source.legalEntityId) : null),
|
|
|
legalEntity: source.legalEntity || source.company || '',
|
|
legalEntity: source.legalEntity || source.company || '',
|
|
|
company: source.company || source.legalEntity || '',
|
|
company: source.company || source.legalEntity || '',
|
|
|
- status: source.formStatus || statusMap[source.status] || source.status || '全职',
|
|
|
|
|
|
|
+ status: this.resolveStatusForForm(source),
|
|
|
hireDate: source.hireDate || source.joinDate || '',
|
|
hireDate: source.hireDate || source.joinDate || '',
|
|
|
factoryId: source.factoryId != null && source.factoryId !== '' ? String(source.factoryId) : null,
|
|
factoryId: source.factoryId != null && source.factoryId !== '' ? String(source.factoryId) : null,
|
|
|
factory: source.factory || source.factoryName || '',
|
|
factory: source.factory || source.factoryName || '',
|
|
@@ -2166,6 +2201,11 @@ export default {
|
|
|
);
|
|
);
|
|
|
return hit ? hit.value : text;
|
|
return hit ? hit.value : text;
|
|
|
},
|
|
},
|
|
|
|
|
+ /** 岗位性质名称快照:按字典 id 反查 label,随 employmentType 一起提交(positionTypeName) */
|
|
|
|
|
+ syncEmploymentTypeName(value) {
|
|
|
|
|
+ const hit = this.employmentOptions.find((item) => String(item.value) === String(value));
|
|
|
|
|
+ this.form.employmentTypeName = hit ? hit.label : '';
|
|
|
|
|
+ },
|
|
|
// 岗位性质(员工档案字段 employmentType):字典 id 作为选项 value,提交后端即字典 id
|
|
// 岗位性质(员工档案字段 employmentType):字典 id 作为选项 value,提交后端即字典 id
|
|
|
async loadEmploymentTypeOptions() {
|
|
async loadEmploymentTypeOptions() {
|
|
|
try {
|
|
try {
|
|
@@ -2184,6 +2224,7 @@ export default {
|
|
|
.filter(Boolean);
|
|
.filter(Boolean);
|
|
|
if (this.form.employmentType) {
|
|
if (this.form.employmentType) {
|
|
|
this.form.employmentType = this.resolveEmploymentType(this.form.employmentType);
|
|
this.form.employmentType = this.resolveEmploymentType(this.form.employmentType);
|
|
|
|
|
+ this.syncEmploymentTypeName(this.form.employmentType);
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
this.employmentOptions = [];
|
|
this.employmentOptions = [];
|
|
@@ -2383,6 +2424,7 @@ export default {
|
|
|
}
|
|
}
|
|
|
if (natureText && (!prime || !this.form.employmentType)) {
|
|
if (natureText && (!prime || !this.form.employmentType)) {
|
|
|
this.form.employmentType = this.resolveEmploymentType(natureText);
|
|
this.form.employmentType = this.resolveEmploymentType(natureText);
|
|
|
|
|
+ this.syncEmploymentTypeName(this.form.employmentType);
|
|
|
}
|
|
}
|
|
|
const names = [];
|
|
const names = [];
|
|
|
const idMap = {};
|
|
const idMap = {};
|