Преглед на файлове

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

lifanagju_citu преди 11 месеца
родител
ревизия
0f5617a4cc

+ 24 - 0
package-lock.json

@@ -9,6 +9,7 @@
       "version": "0.0.0",
       "dependencies": {
         "@mdi/font": "7.0.96",
+        "@vuepic/vue-datepicker": "^8.7.0",
         "axios": "^1.6.8",
         "js-cookie": "^3.0.5",
         "nprogress": "^0.2.0",
@@ -930,6 +931,20 @@
       "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.4.25.tgz",
       "integrity": "sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA=="
     },
+    "node_modules/@vuepic/vue-datepicker": {
+      "version": "8.7.0",
+      "resolved": "https://registry.npmmirror.com/@vuepic/vue-datepicker/-/vue-datepicker-8.7.0.tgz",
+      "integrity": "sha512-EqL51GdaRg6AExVuPCOmnO81n9+oLqgTi+LlST44TwU0UcX0UfefHx1HXwV948fAqBgj0ESgTyDvjXx7EFFL2A==",
+      "dependencies": {
+        "date-fns": "^3.6.0"
+      },
+      "engines": {
+        "node": ">=18.12.0"
+      },
+      "peerDependencies": {
+        "vue": ">=3.2.0"
+      }
+    },
     "node_modules/@vuetify/loader-shared": {
       "version": "2.0.3",
       "resolved": "https://registry.npmmirror.com/@vuetify/loader-shared/-/loader-shared-2.0.3.tgz",
@@ -1250,6 +1265,15 @@
         "node": ">=18"
       }
     },
+    "node_modules/date-fns": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
+      "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/kossnocorp"
+      }
+    },
     "node_modules/debug": {
       "version": "4.3.4",
       "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz",

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
   },
   "dependencies": {
     "@mdi/font": "7.0.96",
+    "@vuepic/vue-datepicker": "^8.7.0",
     "axios": "^1.6.8",
     "js-cookie": "^3.0.5",
     "nprogress": "^0.2.0",

+ 3 - 7
src/components/CtForm/index.vue

@@ -49,12 +49,8 @@
                 :item="item"
                 @change="handleChange(item)"
               ></textareaUI>
-              <datePicker
-                v-model="item.value"
-                v-if="item.type === 'datepicker'"
-                :item="item"
-                @change="handleChange(item)"
-              ></datePicker>
+              <DatePicker v-if="item.type === 'datePicker'" v-model="item.value" :options="item.options" :width="item.width" :class="item.class"></DatePicker>
+              
               <template v-if="item.slotName">
                 <slot :name="item.slotName" :item="item"></slot>
               </template>
@@ -74,7 +70,7 @@ import comboboxUI from './../FormUI/combobox'
 import comboboxZhAndEnUI from './../FormUI/comboboxZhAndEn'
 import radioGroupUI from './../FormUI/radioGroup'
 import textareaUI from './../FormUI/textArea'
-import datePicker from '../FormUI/datePicker'
+import DatePicker from '@/components/DatePicker'
 import { ref, defineEmits } from 'vue'
 const emit = defineEmits(['change', 'inputUpdateAutocomplete'])// 定义一个或多个自定义事件
 const props = defineProps({items: Object})

+ 51 - 0
src/components/DatePicker/index.vue

@@ -0,0 +1,51 @@
+<template>
+  <div style="width: 100%">
+    <VueDatePicker
+      locale="zh-CN"
+      :range="options?.range || false"
+      :model-type="options?.format || 'yyyy.MM.dd'"
+      :month-picker="month"
+      :time-picker="time"
+      :year-picker="year"
+      :placeholder="options.placeholder ?? '请选择'"
+      auto-apply
+      text-input
+      :show-now-button="options.showToday"
+      now-button-label="今天"
+      :enable-time-picker="options.enableTimePicker ?? false"
+      :clearable="options.clearable ?? true"
+      :day-names="['一', '二', '三', '四', '五', '六', '七']"
+      v-bind="$attrs"
+    ></VueDatePicker>
+  </div>
+</template>
+
+<script setup>
+defineOptions({ name: 'date-picker'})
+import { computed } from 'vue';
+
+const props = defineProps({
+  width: {
+    type: [String, Number],
+    default: 300
+  },
+  options: {
+    type: Object,
+    default: () => {}
+  }
+})
+
+const year = computed(() => {
+  return props.options.type === 'year'
+})
+const month = computed(() => {
+  return props.options.type === 'month'
+})
+const time = computed(() => {
+  return props.options.type === 'time'
+})
+</script>
+
+<style scoped lang="scss">
+
+</style>

+ 6 - 0
src/main.js

@@ -15,6 +15,10 @@ import { createPinia } from 'pinia'
 
 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' // pinia 持久化
 
+// 日期组件
+import VueDatePicker from '@vuepic/vue-datepicker';
+import '@vuepic/vue-datepicker/dist/main.css'
+
 import router from './router'
 
 import './permission'
@@ -23,11 +27,13 @@ const pinia = createPinia()
 
 pinia.use(piniaPluginPersistedstate)
 
+
 const app = createApp(App)
 
 app.use(pinia)
 app.use(router)
 
 registerPlugins(app)
+app.component('VueDatePicker', VueDatePicker)
 
 app.mount('#app')

+ 1 - 1
src/views/PersonalCenter/dynamic/left.vue

@@ -17,7 +17,7 @@
           </v-icon>
         </div>
         <div class="userInfo">
-          44岁<span class="vline"></span>{{ baseInfo?.expTypeText || '暂无' }}<span class="vline"></span>{{ baseInfo?.eduTypeText || '暂无' }}
+          {{ baseInfo?.expTypeText || '暂无' }}<span class="vline"></span>{{ baseInfo?.eduTypeText || '暂无' }}
         </div>
         <div class="mt-3">
           <v-select v-model="selectVal" :items="items" density="compact" variant="outlined" item-title="label" item-value="value" hide-details color="primary"></v-select>

+ 45 - 23
src/views/resume/components/projectExperience.vue

@@ -8,8 +8,8 @@
       <h4 class="label-title my-3 mx-2"> {{ type === 'add' ? $t('common.add') : $t('common.edit') }}{{ $t('resume.projectExperience') }}</h4>
       <CtForm ref="formPageRef" :items="items" style="width: 100%;"></CtForm>
       <div class="text-end">
-        <v-btn class="half-button mr-3" variant="tonal" @click="isEdit = false; type = ''">{{ $t('common.cancel') }}</v-btn>
-        <v-btn color="primary" class="half-button" @click="handleSave">{{ $t('common.save') }}</v-btn>
+        <v-btn class="half-button mr-3" variant="tonal" @click="handleCancel">{{ $t('common.cancel') }}</v-btn>
+        <v-btn color="primary" class="half-button" :loading="loading" @click="handleSave">{{ $t('common.save') }}</v-btn>
       </div>
     </div>
     <!-- 展示 -->
@@ -23,9 +23,9 @@
         <div>
           <span style="font-size: 18px; font-weight: bold;">{{ k.name }}</span>
           <span class="label-title ml-5">
-            <span>{{ timesTampChange(k.startTime).slice(0, 10) }}</span>
+            <span>{{ timesTampChange(k.startTime).slice(0, 7) }}</span>
             <span class="mx-1">至</span>
-            <span>{{ timesTampChange(k.endTime).slice(0, 10) }}</span>
+            <span>{{ timesTampChange(k.endTime).slice(0, 7) }}</span>
           </span>
         </div>
       </div>
@@ -38,8 +38,8 @@
 </template>
 
 <script setup name="projectExperience">
-import { ref, shallowRef  } from 'vue'
-import { getTimeStamp, timesTampChange } from '@/utils/date'
+import { ref  } from 'vue'
+import { timesTampChange } from '@/utils/date'
 import { saveResumeProjectExp, getResumeProjectExp, deleteResumeProjectExp } from '@/api/resume'
 import CtForm from '@/components/CtForm'
 import Snackbar from '@/plugins/snackbar'
@@ -49,6 +49,8 @@ const isEdit = ref(false)
 const formPageRef = ref()
 const type = ref('')
 const editId = ref(null)
+const loading = ref(false)
+
 const items = ref({
   options: [
     {
@@ -59,20 +61,30 @@ const items = ref({
       rules: [v => !!v || '请输入项目名称']
     },
     {
-      type: 'datepicker',
+      type: 'datePicker',
       key: 'startTime',
-      value: shallowRef(null),
+      value: null,
       col: 6,
-      label: '项目开始时间 *',
+      class: 'mb-3',
+      options: {
+        type: 'month',
+        format: 'timestamp',
+        placeholder: '项目开始时间 *',
+      },
       flexStyle: 'mr-3',
       rules: [v => !!v || '请选择项目开始时间']
     },
     {
-      type: 'datepicker',
+      type: 'datePicker',
       key: 'endTime',
-      value: shallowRef(null),
+      value: null,
       col: 6,
-      label: '项目结束时间 *',
+      class: 'mb-3',
+      options: {
+        type: 'month',
+        format: 'timestamp',
+        placeholder: '项目结束时间 *',
+      },
       rules: [v => !!v || '请选择项目结束时间']
     },
     {
@@ -95,6 +107,16 @@ const items = ref({
   ]
 })
 
+const handleCancel = () => {
+  isEdit.value = false
+  type.value = ''
+  editId.value = null
+  items.value.options.forEach(e => {
+    if (e.type === 'datePicker') e.value = {}
+    else e.value = null
+  })
+}
+
 // 获取项目经历
 const projectExp = ref([])
 const getResumeTrainExpData = async () => {
@@ -107,26 +129,26 @@ getResumeTrainExpData()
 const handleSave = async () => {
   const { valid } = await formPageRef.value.formRef.validate()
   if (!valid) return
+  loading.value = true
   const obj = {}
   items.value.options.forEach(e => {
-    if (e.type === 'datepicker') obj[e.key] = getTimeStamp(e.value)
-    else obj[e.key] = e.value
+    obj[e.key] = e.value
   })
   if (editId.value) obj.id = editId.value
-  await saveResumeProjectExp(obj)
-  Snackbar.success('保存成功!')
-  isEdit.value = false
-  type.value = ''
-  editId.value = null
-  getResumeTrainExpData()
+  try {
+    await saveResumeProjectExp(obj)
+    Snackbar.success('保存成功!')
+    handleCancel()
+    getResumeTrainExpData()
+  } finally {
+    loading.value = false
+  }
 }
 
 const handleEdit = (item) => {
   editId.value = item.id
   items.value.options.forEach(e => {
-  // 日期相关
-    if (e.type === 'datepicker') e.value = timesTampChange(item[e.key]).slice(0, 10)
-    else e.value = item[e.key]
+    e.value = item[e.key]
   })
   isEdit.value = true
 }

+ 44 - 22
src/views/resume/components/trainingExperience.vue

@@ -8,8 +8,8 @@
       <h4 class="label-title my-3 mx-2"> {{ type === 'add' ? $t('common.add') : $t('common.edit') }}{{ $t('resume.trainingExperience') }}</h4>
       <CtForm ref="formPageRef" :items="items" style="width: 100%;"></CtForm>
       <div class="text-end">
-        <v-btn class="half-button mr-3" variant="tonal" @click="isEdit = false; type = ''">{{ $t('common.cancel') }}</v-btn>
-        <v-btn color="primary" class="half-button" @click="handleSave">{{ $t('common.save') }}</v-btn>
+        <v-btn class="half-button mr-3" variant="tonal" @click="handleCancel">{{ $t('common.cancel') }}</v-btn>
+        <v-btn color="primary" class="half-button" :loading="loading" @click="handleSave">{{ $t('common.save') }}</v-btn>
       </div>
     </div>
     <div v-else>
@@ -23,9 +23,9 @@
             <div>
               <span style="font-size: 18px; font-weight: bold;">{{ k.orgName }}</span>
               <span class="label-title ml-5">
-                <span>{{ timesTampChange(k.startTime).slice(0, 10) }}</span>
+                <span>{{ timesTampChange(k.startTime).slice(0, 7) }}</span>
                 <span class="mx-1">至</span>
-                <span>{{ timesTampChange(k.endTime).slice(0, 10) }}</span>
+                <span>{{ timesTampChange(k.endTime).slice(0, 7) }}</span>
               </span>
             </div>
           </div>
@@ -44,8 +44,8 @@
 </template>
 
 <script setup name="trainingExperience">
-import { ref, shallowRef  } from 'vue'
-import { getTimeStamp, timesTampChange } from '@/utils/date'
+import { ref  } from 'vue'
+import { timesTampChange } from '@/utils/date'
 import { saveResumeTrainExp, getResumeTrainExp, deleteResumeTrainExp } from '@/api/resume'
 import CtForm from '@/components/CtForm'
 import Snackbar from '@/plugins/snackbar'
@@ -55,6 +55,7 @@ const isEdit = ref(false)
 const formPageRef = ref()
 const type = ref('')
 const editId = ref(null)
+const loading = ref(false)
 const items = ref({
   options: [
     {
@@ -75,20 +76,30 @@ const items = ref({
       rules: [v => !!v || '请输入培训课程']
     },
     {
-      type: 'datepicker',
+      type: 'datePicker',
       key: 'startTime',
-      value: shallowRef(null),
+      value: null,
       col: 6,
-      label: '培训开始时间 *',
+      class: 'mb-3',
+      options: {
+        type: 'month',
+        format: 'timestamp',
+        placeholder: '培训开始时间 *',
+      },
       flexStyle: 'mr-3',
       rules: [v => !!v || '请选择培训开始时间']
     },
     {
-      type: 'datepicker',
+      type: 'datePicker',
       key: 'endTime',
-      value: shallowRef(null),
+      value: null,
       col: 6,
-      label: '培训结束时间 *',
+      class: 'mb-3',
+      options: {
+        type: 'month',
+        format: 'timestamp',
+        placeholder: '培训结束时间 *',
+      },
       rules: [v => !!v || '请选择培训结束时间']
     },
     {
@@ -110,6 +121,16 @@ const items = ref({
   ]
 })
 
+const handleCancel = () => {
+  isEdit.value = false
+  type.value = ''
+  editId.value = null
+  items.value.options.forEach(e => {
+    if (e.type === 'datePicker') e.value = {}
+    else e.value = null
+  })
+}
+
 // 获取培训经历
 const trainExp = ref([])
 const getResumeTrainExpData = async () => {
@@ -122,25 +143,26 @@ getResumeTrainExpData()
 const handleSave = async () => {
   const { valid } = await formPageRef.value.formRef.validate()
   if (!valid) return
+  loading.value = true
   const obj = {}
   items.value.options.forEach(e => {
-    if (e.key === 'startTime' || e.key == 'endTime') obj[e.key] = getTimeStamp(e.value)
-    else obj[e.key] = e.value
+    obj[e.key] = e.value
   })
   if (editId.value) obj.id = editId.value
-  await saveResumeTrainExp(obj)
-  Snackbar.success('保存成功!')
-  isEdit.value = false
-  type.value = ''
-  editId.value = null
-  getResumeTrainExpData()
+  try {
+    await saveResumeTrainExp(obj)
+    Snackbar.success('保存成功!')
+    handleCancel()
+    getResumeTrainExpData()
+  } finally {
+    loading.value = false
+  }
 }
 
 const handleEdit = (item) => {
   editId.value = item.id
   items.value.options.forEach(e => {
-    if (e.key === 'startTime' || e.key == 'endTime') e.value = timesTampChange(item[e.key]).slice(0, 10)
-    else e.value = item[e.key]
+    e.value = item[e.key]
   })
   isEdit.value = true
 }