|
|
@@ -40,13 +40,13 @@
|
|
|
</a-col>
|
|
|
<a-col :span="8">
|
|
|
<a-form-item id="PersonalInfoForm-nation" label="民族" name="nation" v-bind="validateInfos.nation">
|
|
|
- <a-input v-model:value="formData.nation" allow-clear placeholder="请输入民族"></a-input>
|
|
|
+ <a-select v-model:value="formData.nation" :options="ethnicityOptions" allow-clear placeholder="请选择民族" />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<!-- 第三行 -->
|
|
|
<a-col :span="8">
|
|
|
<a-form-item id="PersonalInfoForm-nationality" label="国籍" name="nationality" v-bind="validateInfos.nationality">
|
|
|
- <a-input v-model:value="formData.nationality" allow-clear placeholder="请输入国籍"></a-input>
|
|
|
+ <a-select v-model:value="formData.nationality" :options="nationalityOptions" allow-clear placeholder="请选择国籍" />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<a-col :span="8">
|
|
|
@@ -56,7 +56,7 @@
|
|
|
</a-col>
|
|
|
<a-col :span="8">
|
|
|
<a-form-item id="PersonalInfoForm-education" label="学历" name="education" v-bind="validateInfos.education">
|
|
|
- <a-input v-model:value="formData.education" allow-clear placeholder="请输入学历"></a-input>
|
|
|
+ <a-select v-model:value="formData.education" :options="educationOptions" allow-clear placeholder="请选择学历" />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<!-- 第四行 -->
|
|
|
@@ -91,7 +91,6 @@
|
|
|
<a-select v-model:value="formData.householdType" :options="householdTypeOptions" allow-clear placeholder="请选择户口性质" />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
- <!-- 第六行 -->
|
|
|
<a-col :span="8">
|
|
|
<a-form-item
|
|
|
id="PersonalInfoForm-householdLocation"
|
|
|
@@ -99,7 +98,16 @@
|
|
|
name="householdLocation"
|
|
|
v-bind="validateInfos.householdLocation"
|
|
|
>
|
|
|
- <a-input v-model:value="formData.householdLocation" allow-clear placeholder="请输入户口所在地"></a-input>
|
|
|
+ <a-tree-select
|
|
|
+ v-model:value="householdValueObj"
|
|
|
+ v-model:tree-expanded-keys="householdExpandedKeys"
|
|
|
+ :tree-data="householdTreeData"
|
|
|
+ :load-data="(node) => loadTreeChildren(node, 'householdTreeData')"
|
|
|
+ placeholder="请选择户口所在地"
|
|
|
+ allow-clear
|
|
|
+ label-in-value
|
|
|
+ @change="(val) => handleAreaChange(val, 'household')"
|
|
|
+ />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<a-col :span="8">
|
|
|
@@ -109,7 +117,16 @@
|
|
|
name="currentResidence"
|
|
|
v-bind="validateInfos.currentResidence"
|
|
|
>
|
|
|
- <a-input v-model:value="formData.currentResidence" allow-clear placeholder="请输入现居住地"></a-input>
|
|
|
+ <a-tree-select
|
|
|
+ v-model:value="residenceValueObj"
|
|
|
+ v-model:tree-expanded-keys="residenceExpandedKeys"
|
|
|
+ :tree-data="residenceTreeData"
|
|
|
+ :load-data="(node) => loadTreeChildren(node, 'residenceTreeData')"
|
|
|
+ placeholder="请选择现居住地"
|
|
|
+ allow-clear
|
|
|
+ label-in-value
|
|
|
+ @change="(val) => handleAreaChange(val, 'residence')"
|
|
|
+ />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<a-col :span="8">
|
|
|
@@ -161,7 +178,7 @@
|
|
|
name="isOverseasTalent"
|
|
|
v-bind="validateInfos.isOverseasTalent"
|
|
|
>
|
|
|
- <a-input v-model:value="formData.isOverseasTalent" allow-clear placeholder="请输入是否留学人才"></a-input>
|
|
|
+ <a-select v-model:value="formData.isOverseasTalent" :options="yesNoOptions" allow-clear placeholder="请选择是否留学人才" />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<!-- 第九行 -->
|
|
|
@@ -182,7 +199,7 @@
|
|
|
name="acceptRecommend"
|
|
|
v-bind="validateInfos.acceptRecommend"
|
|
|
>
|
|
|
- <a-input v-model:value="formData.acceptRecommend" allow-clear placeholder="请输入是否接受公共就业服务机构推荐职位"></a-input>
|
|
|
+ <a-select v-model:value="formData.acceptRecommend" :options="yesNoOptions" allow-clear placeholder="请选择是否接受推荐职位" />
|
|
|
</a-form-item>
|
|
|
</a-col>
|
|
|
<!-- 第十行 -->
|
|
|
@@ -214,6 +231,7 @@
|
|
|
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
|
|
|
import JImageUpload from '@/components/Form/src/jeecg/components/JImageUpload.vue';
|
|
|
import { useDict } from '/@/hooks/dictionary/useDict';
|
|
|
+ import { defHttp } from '/@/utils/http/axios';
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
|
const props = defineProps({
|
|
|
@@ -226,33 +244,35 @@
|
|
|
const emit = defineEmits(['register', 'ok']);
|
|
|
const formData = reactive<Record<string, any>>({
|
|
|
id: '',
|
|
|
- idType: '',
|
|
|
+ idType: undefined,
|
|
|
idNumber: '',
|
|
|
fullName: '',
|
|
|
- gender: '',
|
|
|
+ gender: undefined,
|
|
|
birthDate: '',
|
|
|
- nation: '',
|
|
|
- nationality: '',
|
|
|
- maritalStatus: '',
|
|
|
- education: '',
|
|
|
+ nation: undefined,
|
|
|
+ nationality: undefined,
|
|
|
+ maritalStatus: undefined,
|
|
|
+ education: undefined,
|
|
|
graduationDate: '',
|
|
|
graduateSchool: '',
|
|
|
major: '',
|
|
|
- politicalStatus: '',
|
|
|
- workExperience: '',
|
|
|
- householdType: '',
|
|
|
+ politicalStatus: undefined,
|
|
|
+ workExperience: undefined,
|
|
|
+ householdType: undefined,
|
|
|
householdLocation: '',
|
|
|
+ householdAreaName: '',
|
|
|
currentResidence: '',
|
|
|
+ residenceAreaName: '',
|
|
|
currentAddress: '',
|
|
|
- jobSeekerCategory: '',
|
|
|
+ jobSeekerCategory: undefined,
|
|
|
contactPhone: '',
|
|
|
email: '',
|
|
|
qqNumber: '',
|
|
|
wechatId: '',
|
|
|
- isOverseasTalent: '',
|
|
|
+ isOverseasTalent: undefined,
|
|
|
skillLevel: '',
|
|
|
- jobSearchStatus: '',
|
|
|
- acceptRecommend: '',
|
|
|
+ jobSearchStatus: undefined,
|
|
|
+ acceptRecommend: undefined,
|
|
|
avatarPath: '',
|
|
|
tagIds: [],
|
|
|
dataSource: '2',
|
|
|
@@ -273,6 +293,9 @@
|
|
|
'JobSeekerCategory',
|
|
|
'JobSeekerStatus',
|
|
|
'DataSource',
|
|
|
+ 'Ethnicity',
|
|
|
+ 'Nationality',
|
|
|
+ 'Education',
|
|
|
]);
|
|
|
|
|
|
// 将预加载的字典转为 a-select 的 options
|
|
|
@@ -285,11 +308,117 @@
|
|
|
const jobSeekerCategoryOptions = computed(() => getDictOptions('JobSeekerCategory'));
|
|
|
const jobSearchStatusOptions = computed(() => getDictOptions('JobSeekerStatus'));
|
|
|
const dataSourceOptions = computed(() => getDictOptions('DataSource'));
|
|
|
+ const ethnicityOptions = computed(() => getDictOptions('Ethnicity'));
|
|
|
+ const nationalityOptions = computed(() => getDictOptions('Nationality'));
|
|
|
+ const educationOptions = computed(() => getDictOptions('Education'));
|
|
|
+ const yesNoOptions = ref([
|
|
|
+ { label: '是', value: '1' },
|
|
|
+ { label: '否', value: '0' },
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // ---------- 树形下拉:行政区划懒加载+服务端搜索展开 ----------
|
|
|
+ // 户口所在地树数据
|
|
|
+ const householdTreeData = ref<any[]>([]);
|
|
|
+ // 户口所在地 labelInValue 对象(用于编辑回显)
|
|
|
+ const householdValueObj = ref<any>(undefined);
|
|
|
+ // 户口所在地展开节点 code 列表(搜索时自动展开匹配项所在分支)
|
|
|
+ const householdExpandedKeys = ref<string[]>([]);
|
|
|
+
|
|
|
+ // 现居住地树数据
|
|
|
+ const residenceTreeData = ref<any[]>([]);
|
|
|
+ // 现居住地 labelInValue 对象(用于编辑回显)
|
|
|
+ const residenceValueObj = ref<any>(undefined);
|
|
|
+ // 现居住地展开节点 code 列表
|
|
|
+ const residenceExpandedKeys = ref<string[]>([]);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加载行政区划树根节点(省级)
|
|
|
+ */
|
|
|
+ async function loadAreaRootNodes() {
|
|
|
+ const res = await defHttp.get({
|
|
|
+ url: '/system/dictionary/getDictTreeChildren',
|
|
|
+ params: { dictionaryCode: 'XZQH', parentCode: '' },
|
|
|
+ }, { isTransformResponse: false });
|
|
|
+ if (res.success && res.result) {
|
|
|
+ return res.result.map((item) => ({
|
|
|
+ key: item.key,
|
|
|
+ title: item.title,
|
|
|
+ value: item.key,
|
|
|
+ isLeaf: item.leaf,
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 懒加载行政区划树的子节点(按需加载,一次只加载展开节点的下一级)
|
|
|
+ * @param treeNode a-tree-select 展开的节点对象
|
|
|
+ * @param treeDataRefName 对应 treeData 的 ref 名称(householdTreeData / residenceTreeData)
|
|
|
+ */
|
|
|
+ async function loadTreeChildren(treeNode, treeDataRefName) {
|
|
|
+ // 避免重复加载
|
|
|
+ if (treeNode.dataRef.children) {
|
|
|
+ return Promise.resolve();
|
|
|
+ }
|
|
|
+ const res = await defHttp.get({
|
|
|
+ url: '/system/dictionary/getDictTreeChildren',
|
|
|
+ params: { dictionaryCode: 'XZQH', parentCode: treeNode.value },
|
|
|
+ }, { isTransformResponse: false });
|
|
|
+ if (res.success && res.result) {
|
|
|
+ const children = res.result.map((item) => ({
|
|
|
+ key: item.key,
|
|
|
+ title: item.title,
|
|
|
+ value: item.key,
|
|
|
+ isLeaf: item.leaf,
|
|
|
+ }));
|
|
|
+ // 将子节点挂到 dataRef 上
|
|
|
+ treeNode.dataRef.children = children;
|
|
|
+ // 触发响应式更新
|
|
|
+ if (treeDataRefName === 'householdTreeData') {
|
|
|
+ householdTreeData.value = [...householdTreeData.value];
|
|
|
+ } else {
|
|
|
+ residenceTreeData.value = [...residenceTreeData.value];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Promise.resolve();
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * 行政区划选择变更处理
|
|
|
+ * - 同步更新 formData 中的 code 字段(householdLocation / currentResidence)
|
|
|
+ * - 调后端 API 获取完整路径,填入 areaName 字段(householdAreaName / residenceAreaName)
|
|
|
+ * - 更新 valueObj.label 为完整路径,使下拉框直接显示完整路径文本
|
|
|
+ */
|
|
|
+ async function handleAreaChange(val, prefix) {
|
|
|
+ if (val && val.value) {
|
|
|
+ formData[`${prefix}Location`] = val.value;
|
|
|
+ // 获取完整路径,同时用于 areaName 字段存储和下拉框 label 显示
|
|
|
+ const res = await defHttp.get({
|
|
|
+ url: '/system/dictionary/getItemFullPath',
|
|
|
+ params: { dictionaryCode: 'XZQH', code: val.value },
|
|
|
+ }, { isTransformResponse: false });
|
|
|
+ const fullPath = res.success ? res.result : val.label;
|
|
|
+ formData[`${prefix}AreaName`] = fullPath;
|
|
|
+ // 同步更新下拉框展示文本为完整路径
|
|
|
+ if (prefix === 'household') {
|
|
|
+ householdValueObj.value = { value: val.value, label: fullPath };
|
|
|
+ } else {
|
|
|
+ residenceValueObj.value = { value: val.value, label: fullPath };
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ formData[`${prefix}Location`] = '';
|
|
|
+ formData[`${prefix}AreaName`] = '';
|
|
|
+ if (prefix === 'household') {
|
|
|
+ householdValueObj.value = undefined;
|
|
|
+ } else {
|
|
|
+ residenceValueObj.value = undefined;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
// 个人标签选项列表(从后端加载)
|
|
|
const personalTagOptions = ref<any[]>([]);
|
|
|
|
|
|
- // 组件挂载时加载个人标签列表
|
|
|
+ // 组件挂载时加载个人标签列表和行政区划树
|
|
|
onMounted(async () => {
|
|
|
try {
|
|
|
const res = await getPersonalTagListForSelect();
|
|
|
@@ -300,6 +429,10 @@
|
|
|
} catch {
|
|
|
personalTagOptions.value = [];
|
|
|
}
|
|
|
+ // 加载行政区划树根节点(省级),两个下拉共用相同根节点数据
|
|
|
+ const rootNodes = await loadAreaRootNodes();
|
|
|
+ householdTreeData.value = rootNodes;
|
|
|
+ residenceTreeData.value = rootNodes;
|
|
|
});
|
|
|
|
|
|
//表单验证
|
|
|
@@ -309,19 +442,19 @@
|
|
|
fullName: [{ required: true, message: '请输入姓名' }],
|
|
|
gender: [{ required: true, message: '请选择性别' }],
|
|
|
birthDate: [{ required: true, message: '请选择出生日期' }],
|
|
|
- nation: [{ required: true, message: '请输入民族' }],
|
|
|
- nationality: [{ required: true, message: '请输入国籍' }],
|
|
|
- education: [{ required: true, message: '请输入学历' }],
|
|
|
+ nation: [{ required: true, message: '请选择民族' }],
|
|
|
+ nationality: [{ required: true, message: '请选择国籍' }],
|
|
|
+ education: [{ required: true, message: '请选择学历' }],
|
|
|
graduationDate: [{ required: true, message: '请选择毕业日期' }],
|
|
|
graduateSchool: [{ required: true, message: '请输入毕业院校' }],
|
|
|
workExperience: [{ required: true, message: '请选择工作经验' }],
|
|
|
- householdLocation: [{ required: true, message: '请输入户口所在地' }],
|
|
|
- currentResidence: [{ required: true, message: '请输入现居住地' }],
|
|
|
+ householdLocation: [{ required: true, message: '请选择户口所在地' }],
|
|
|
+ currentResidence: [{ required: true, message: '请选择现居住地' }],
|
|
|
jobSeekerCategory: [{ required: true, message: '请选择求职人员类别' }],
|
|
|
contactPhone: [{ required: true, message: '请输入联系电话' }],
|
|
|
- isOverseasTalent: [{ required: true, message: '请输入是否留学人才' }],
|
|
|
+ isOverseasTalent: [{ required: true, message: '请选择是否留学人才' }],
|
|
|
jobSearchStatus: [{ required: true, message: '请选择求职状态' }],
|
|
|
- acceptRecommend: [{ required: true, message: '请输入是否接受公共就业服务机构推荐职位' }],
|
|
|
+ acceptRecommend: [{ required: true, message: '请选择是否接受推荐职位' }],
|
|
|
});
|
|
|
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
|
|
|
//日期个性化选择
|
|
|
@@ -374,6 +507,13 @@
|
|
|
}
|
|
|
//赋值
|
|
|
Object.assign(formData, tmpData);
|
|
|
+ // 回填行政区划树形下拉的 label 显示(直接用已存储的完整路径文本,无需调 API)
|
|
|
+ householdValueObj.value = tmpData.householdLocation
|
|
|
+ ? { value: tmpData.householdLocation, label: tmpData.householdAreaName || tmpData.householdLocation }
|
|
|
+ : undefined;
|
|
|
+ residenceValueObj.value = tmpData.currentResidence
|
|
|
+ ? { value: tmpData.currentResidence, label: tmpData.residenceAreaName || tmpData.currentResidence }
|
|
|
+ : undefined;
|
|
|
});
|
|
|
}
|
|
|
|