|
@@ -0,0 +1,252 @@
|
|
|
+<template>
|
|
|
+ <div class="resume-box">
|
|
|
+ <div class="resume-header mb-3">
|
|
|
+ <div class="resume-title">{{ $t('resume.workExperience') }}</div>
|
|
|
+ <v-btn variant="text" color="primary" prepend-icon="mdi-plus-box" @click="handle(0)">{{ $t('common.add') }}</v-btn>
|
|
|
+ </div>
|
|
|
+ <!-- 编辑-表单 -->
|
|
|
+ <div v-if="isEdit" class="educExpItem-edit">
|
|
|
+ <h4 class="color6 my-3 mx-2"> {{ titleStatus ? $t('common.edit') : $t('common.add') }}{{ $t('resume.workExperience') }}</h4>
|
|
|
+ <CtForm ref="CtFormRef" :items="formItems" style="width: 100%;"></CtForm>
|
|
|
+ <div class="text-end mt-3">
|
|
|
+ <v-btn class="half-button mr-3" variant="tonal" @click="isEdit = false">{{ $t('common.cancel') }}</v-btn>
|
|
|
+ <v-btn color="primary" class="half-button" @click="handleSave">{{ $t('common.save') }}</v-btn>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- 展示 -->
|
|
|
+ <div v-else-if="!dataList?.length" class="resumeNoDataText">{{ $t('resume.dataDefaultPrompt') }}{{ $t('resume.workExperience') }}...</div>
|
|
|
+ <div
|
|
|
+ v-else
|
|
|
+ v-for="(item, index) in dataList" :key="'workExperience' + index"
|
|
|
+ :class="[' mx-n2', {'mt-5': index }]"
|
|
|
+ >
|
|
|
+ <div class="educExpItem" @mouseenter="item.active = true" @mouseleave="item.active = false">
|
|
|
+ <div class="level1 d-flex align-center justify-space-between" style="height: 40px;">
|
|
|
+ <div>
|
|
|
+ <span style="font-size: 18px; font-weight: bold;">{{ item.enterpriseName }}</span>
|
|
|
+ <span class="color6 font15 ml-5">
|
|
|
+ <span>{{ timesTampChange(item.startTime).slice(0, 10) }}</span>
|
|
|
+ <span class="mx-1">至</span>
|
|
|
+ <span>{{ timesTampChange(item.endTime).slice(0, 10) }}</span>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div v-if="item.active">
|
|
|
+ <v-btn variant="text" color="primary" prepend-icon="mdi-square-edit-outline" @click="handle(item)">{{ $t('common.edit') }}</v-btn>
|
|
|
+ <v-btn variant="text" color="primary" prepend-icon="mdi-trash-can-outline" @click="handleDelete(item)">{{ $t('common.delete') }}</v-btn>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="level2 my-2">
|
|
|
+ <span class="color6 font15">{{ item.positionName }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="level3">
|
|
|
+ <span class="color6 font15">工作内容:{{ item.content }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="workExperience">
|
|
|
+import CtForm from '@/components/CtForm'
|
|
|
+import Snackbar from '@/plugins/snackbar'
|
|
|
+import { getDict } from '@/hooks/web/useDictionaries'
|
|
|
+import { getTimeStamp, timesTampChange } from '@/utils/date'
|
|
|
+import { saveResumeWorkExp, getResumeWorkExp, deleteResumeWorkExp, enterpriseSearchByName } from '@/api/resume'
|
|
|
+import Confirm from '@/plugins/confirm'
|
|
|
+import { dealCanBeInputtedSave, dealCanBeInputtedValueAndLabel } from '@/utils/getText'
|
|
|
+import { debounce } from 'lodash'
|
|
|
+import { nextTick, shallowRef, reactive, ref } from 'vue'
|
|
|
+const editId = ref(null)
|
|
|
+const CtFormRef = ref()
|
|
|
+const dictItemsObj = reactive({})
|
|
|
+dictItemsObj.educationSystemType = [{ label: '全日制', value: '0' }, { label: '非全日制', value: '1' }]
|
|
|
+
|
|
|
+// 企业名称下拉列表
|
|
|
+const getSchoolListData = async (name, init = '') => {
|
|
|
+ const item = formItems.value.options.find(e => e.key === 'enterpriseId')
|
|
|
+ if (!item) return
|
|
|
+ if (!init) item.value = null
|
|
|
+ item[item.itemTextName] = name
|
|
|
+ const data = await enterpriseSearchByName({ name })
|
|
|
+ item.items = data
|
|
|
+}
|
|
|
+const debouncedCallbackSchool = debounce(newValue => {
|
|
|
+ getSchoolListData(newValue)
|
|
|
+}, 500)
|
|
|
+
|
|
|
+const positionSearch = (name, init = '') => {
|
|
|
+ const item = formItems.value.options.find(e => e.key === 'positionId')
|
|
|
+ if (!item) return
|
|
|
+ if (!init) item.value = ''
|
|
|
+ item[item.itemTextName] = name
|
|
|
+}
|
|
|
+
|
|
|
+const formItems = ref({
|
|
|
+ options: [
|
|
|
+ {
|
|
|
+ type: 'combobox',
|
|
|
+ key: 'enterpriseId',
|
|
|
+ value: null,
|
|
|
+ default: null,
|
|
|
+ label: '企业名称 *',
|
|
|
+ col: 6,
|
|
|
+ outlined: true,
|
|
|
+ clearable: true,
|
|
|
+ canBeInputted: true, //
|
|
|
+ itemTextName: 'enterpriseName',
|
|
|
+ itemText: 'value',
|
|
|
+ itemValue: 'key',
|
|
|
+ rules: [v => !!v || '请选择企业名称'],
|
|
|
+ search: debouncedCallbackSchool,
|
|
|
+ items: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'combobox',
|
|
|
+ key: 'positionId',
|
|
|
+ value: null,
|
|
|
+ default: null,
|
|
|
+ label: '职位名称 *',
|
|
|
+ col: 6,
|
|
|
+ outlined: true,
|
|
|
+ clearable: true,
|
|
|
+ canBeInputted: true, //
|
|
|
+ itemTextName: 'positionName',
|
|
|
+ itemText: 'nameCn',
|
|
|
+ itemValue: 'id',
|
|
|
+ rules: [v => !!v || '请选择职位名称'],
|
|
|
+ search: val => positionSearch(val),
|
|
|
+ items: []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'datepicker',
|
|
|
+ key: 'startTime',
|
|
|
+ value: shallowRef(null),
|
|
|
+ col: 6,
|
|
|
+ label: '起始时间 *',
|
|
|
+ rules: [v => !!v || '请选择起始时间']
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'datepicker',
|
|
|
+ key: 'endTime',
|
|
|
+ value: shallowRef(null),
|
|
|
+ col: 6,
|
|
|
+ label: '结束时间 *',
|
|
|
+ rules: [v => !!v || '请选择结束时间']
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'textarea',
|
|
|
+ key: 'content',
|
|
|
+ value: null,
|
|
|
+ default: null,
|
|
|
+ counter: 1600,
|
|
|
+ label: '工作内容 *',
|
|
|
+ outlined: true,
|
|
|
+ rules: [v => !!v || '请输入工作内容']
|
|
|
+ },
|
|
|
+ ]
|
|
|
+})
|
|
|
+// 左侧加mr
|
|
|
+formItems.value.options.forEach((e, index) => {
|
|
|
+ if (((index + 2) % 2 === 0) && Boolean(e.col) && e.col !== 12) e.flexStyle = 'mr-3'
|
|
|
+})
|
|
|
+
|
|
|
+console.log('dictItemsObj', dictItemsObj)
|
|
|
+// 获取数据
|
|
|
+const dataList = ref([])
|
|
|
+const getData = async () => {
|
|
|
+ const data = await getResumeWorkExp()
|
|
|
+ dataList.value = data
|
|
|
+}
|
|
|
+getData()
|
|
|
+
|
|
|
+// 新增 或 编辑
|
|
|
+const isEdit = ref(false)
|
|
|
+const titleStatus = ref(0)
|
|
|
+const handle = (item) => {
|
|
|
+ titleStatus.value = item ? 1 : 0
|
|
|
+ // if (!positionData.value || !positionData.value.length) getPositionData ()
|
|
|
+ if (item) { // 编辑
|
|
|
+ editId.value = item.id
|
|
|
+ formItems.value.options.forEach(e => { // 回显
|
|
|
+ if (e.canBeInputted) { // 特殊处理可输入下拉框
|
|
|
+ dealCanBeInputtedValueAndLabel(e, item)
|
|
|
+ }
|
|
|
+ else if (e.type === 'datepicker') e.value = timesTampChange(item[e.key]).slice(0, 10)
|
|
|
+ else if (item[e.key]) e.value = item[e.key]
|
|
|
+ })
|
|
|
+ } else { // 新增
|
|
|
+ editId.value = null
|
|
|
+ formItems.value.options.forEach(e => e.value = e.default || null)
|
|
|
+ }
|
|
|
+ nextTick(() => {
|
|
|
+ isEdit.value = true
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 保存-基础信息
|
|
|
+const handleSave = async () => {
|
|
|
+ const { valid } = await CtFormRef.value.formRef.validate()
|
|
|
+ if (!valid) return
|
|
|
+ const obj = {}
|
|
|
+ formItems.value.options.forEach(e => {
|
|
|
+ if (e.canBeInputted) { // 特殊处理可输入下拉框
|
|
|
+ dealCanBeInputtedSave(e, obj)
|
|
|
+ }
|
|
|
+ else if (e.type === 'datepicker') obj[e.key] = getTimeStamp(e.value)
|
|
|
+ else obj[e.key] = e.value
|
|
|
+ })
|
|
|
+ if (editId.value) obj.id = editId.value
|
|
|
+ await saveResumeWorkExp(obj)
|
|
|
+ Snackbar.success('保存成功!')
|
|
|
+ isEdit.value = false
|
|
|
+ await getData()
|
|
|
+}
|
|
|
+
|
|
|
+// 删除数据
|
|
|
+const handleDelete = ({ id }) => {
|
|
|
+ Confirm('系统提示', '是否确认删除此教育经历?').then(async () => {
|
|
|
+ await deleteResumeWorkExp(id)
|
|
|
+ nextTick(() => {
|
|
|
+ getData(id)
|
|
|
+ Snackbar.success('删除成功!')
|
|
|
+ })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 获取字典内容
|
|
|
+const dictList = [
|
|
|
+ { type: 'positionData', key: 'positionId' }
|
|
|
+]
|
|
|
+const getDictData = async (obj) => {
|
|
|
+ const item = formItems.value.options.find(e => e.key === obj.key)
|
|
|
+ if (item) { // && !item.items?.length
|
|
|
+ const { data } = await getDict(obj.type, null, obj.type)
|
|
|
+ item.items = data || []
|
|
|
+ dictItemsObj[obj.key] = data || []
|
|
|
+ }
|
|
|
+}
|
|
|
+const getOptions = () => {
|
|
|
+ dictList.forEach(obj => getDictData(obj))
|
|
|
+}
|
|
|
+getOptions()
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.font15 { font-size: 15px;; }
|
|
|
+.color9 { color: #999; }
|
|
|
+.color6 { color: #666666; }
|
|
|
+.educExpItem {
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 2px 10px 8px;
|
|
|
+ &:hover {
|
|
|
+ background-color: #f8f8f8;
|
|
|
+ }
|
|
|
+}
|
|
|
+.educExpItem-edit {
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 2px 10px 8px;
|
|
|
+ background-color: #f8f8f8;
|
|
|
+}
|
|
|
+</style>
|