فهرست منبع

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

lifanagju_citu 9 ماه پیش
والد
کامیت
588372b033

+ 110 - 0
src/api/menduner/system/person/index.ts

@@ -0,0 +1,110 @@
+import request from '@/config/axios'
+
+// 人才信息 VO
+export interface PersonInfoVO {
+  id: number // id
+  userId: number // 用户id
+  name: string // 真实姓名
+  sex: string // 用户性别
+  avatar: string // 头像地址
+  phone: string // 联系手机号
+  email: string // 用户邮箱
+  wxCode: string // 微信号
+  birthday: Date // 出生日期
+  maritalStatus: string // 婚姻状况(0未婚 1已婚 2离异 3保密)
+  areaId: number // 现居住地
+  jobType: string // 求职类型(0全职 1兼职 2临时 3实习)
+  jobStatus: string // 求职状态(0离职-随时到岗 1在职-月内到岗 2在职-考虑机会 3在职-暂不考虑)
+  firstWorkTime: Date // 首次工作时间
+  advantage: string // 个人优势
+  expType: string // 工作经验
+  eduType: string // 学历
+}
+
+// 人才信息 API
+export const PersonInfoApi = {
+  // 查询人才信息分页
+  getPersonInfoPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/person-info/page`, params })
+  },
+
+  // 查询人才信息详情
+  getPersonInfo: async (id: number) => {
+    return await request.get({ url: `/menduner/system/person-info/get?id=` + id })
+  },
+
+  // 新增人才信息
+  createPersonInfo: async (data: PersonInfoVO) => {
+    return await request.post({ url: `/menduner/system/person-info/create`, data })
+  },
+
+  // 修改人才信息
+  updatePersonInfo: async (data: PersonInfoVO) => {
+    return await request.put({ url: `/menduner/system/person-info/update`, data })
+  },
+
+  // 删除人才信息
+  deletePersonInfo: async (id: number) => {
+    return await request.delete({ url: `/menduner/system/person-info/delete?id=` + id })
+  },
+
+  // 导出人才信息 Excel
+  exportPersonInfo: async (params) => {
+    return await request.download({ url: `/menduner/system/person-info/export-excel`, params })
+  },
+
+  // 查询人才档案
+  getPersonDetails: async (id: string) => {
+    return await request.get({ url: `/menduner/system/person-info/get?id=` + id })
+  },
+
+  // 获取用户账户
+  getPersonAccount: async (userId: string) => {
+    return await request.get({ url: `/menduner/system/user-account/get?userId=` + userId })
+  },
+
+  // 获得用户钱包明细
+  getPersonWallet: async (userId: string) => {
+    return await request.get({ url: `/pay/wallet/get?userId=` + userId })
+  },
+
+  // 教育经历分页
+  getPersonEduPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/edu-exp/page`, params })
+  },
+
+  // 工作经历分页
+  getPersonExpPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/work-exp/page`, params })
+  },
+
+  // 项目经历分页
+  getPersonProjectPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/project-exp/page`, params })
+  },
+
+  // 求职意向分页
+  getPersonJobIntentionPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/job-interested/page`, params })
+  },
+
+  // 获得钱包充值记录分页
+  getPersonWalletRechargePage: async (params: any) => {
+    return await request.get({ url: `/pay/wallet-recharge/page`, params })
+  },
+
+  // 积分变动分页
+  getPersonAccountRecordPage: async (params: any) => {
+    return await request.get({ url: `/menduner/system/user/account/record/page`, params })
+  },
+
+  // 根据用户编号获取招聘职位收藏数量
+  getPersonJobFavoriteCount: async (userId: string) => {
+    return await request.get({ url: `/menduner/system/person-job-favorite/count?userId=` + userId })
+  },
+
+  // 根据用户编号获取企业关注订阅数量
+  getPersonEnterpriseSubscribeCount: async (userId: string) => {
+    return await request.get({ url: `/menduner/system/person-enterprise-subscribe/count?userId=` + userId })
+  }
+}

+ 18 - 0
src/router/modules/remaining.ts

@@ -485,6 +485,24 @@ const remainingRouter: AppRouteRecordRaw[] = [
       }
     ]
   },
+  {
+    path: '/person',
+    component: Layout,
+    name: 'PersonCenter',
+    meta: { hidden: true },
+    children: [
+      {
+        path: 'person/detail',
+        name: 'PersonDetail',
+        meta: {
+          title: '人才详情',
+          noCache: true,
+          hidden: true
+        },
+        component: () => import('@/views/menduner/system/person/details/index.vue')
+      }
+    ]
+  },
   {
     path: '/order',
     component: Layout,

+ 3 - 0
src/utils/dict.ts

@@ -238,4 +238,7 @@ export enum DICT_TYPE {
   MENDUNER_TRADE_ORDER_CANCEL_TYPE = 'menduner_trade_order_cancel_type', // 订单取消类型
   MENDUNER_USER_TYPE = 'menduner_user_type', // 用户类型
   MENDUNER_SEX = 'menduner_sex', // 性别
+  MENDUNER_EXP_TYPE = 'menduner_exp_type', // 工作经验
+  MENDUNER_JOB_STATUS = 'menduner_job_status', // 求职状态
+  MENDUNER_MARITAL_STATUS = 'menduner_marital_status', // 婚姻状况
 }

+ 181 - 0
src/views/menduner/system/person/PersonInfoForm.vue

@@ -0,0 +1,181 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="真实姓名" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入真实姓名" />
+      </el-form-item>
+      <el-form-item label="用户性别" prop="sex">
+        <el-radio-group v-model="formData.sex">
+          <el-radio label="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="头像地址" prop="avatar">
+        <el-input v-model="formData.avatar" placeholder="请输入头像地址" />
+      </el-form-item>
+      <el-form-item label="联系手机号" prop="phone">
+        <el-input v-model="formData.phone" placeholder="请输入联系手机号" />
+      </el-form-item>
+      <el-form-item label="用户邮箱" prop="email">
+        <el-input v-model="formData.email" placeholder="请输入用户邮箱" />
+      </el-form-item>
+      <el-form-item label="微信号" prop="wxCode">
+        <el-input v-model="formData.wxCode" placeholder="请输入微信号" />
+      </el-form-item>
+      <el-form-item label="出生日期" prop="birthday">
+        <el-input v-model="formData.birthday" placeholder="请输入出生日期" />
+      </el-form-item>
+      <el-form-item label="婚姻状况" prop="maritalStatus">
+        <el-radio-group v-model="formData.maritalStatus">
+          <el-radio label="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="现居住地" prop="areaId">
+        <el-input v-model="formData.areaId" placeholder="请输入现居住地" />
+      </el-form-item>
+      <el-form-item label="求职类型" prop="jobType">
+        <el-select v-model="formData.jobType" placeholder="请选择求职类型">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="求职状态" prop="jobStatus">
+        <el-radio-group v-model="formData.jobStatus">
+          <el-radio label="1">请选择字典生成</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="首次工作时间" prop="firstWorkTime">
+        <el-date-picker
+          v-model="formData.firstWorkTime"
+          type="date"
+          value-format="x"
+          placeholder="选择首次工作时间"
+        />
+      </el-form-item>
+      <el-form-item label="个人优势" prop="advantage">
+        <el-input v-model="formData.advantage" placeholder="请输入个人优势" />
+      </el-form-item>
+      <el-form-item label="工作经验" prop="expType">
+        <el-select v-model="formData.expType" placeholder="请选择工作经验">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="学历" prop="eduType">
+        <el-select v-model="formData.eduType" placeholder="请选择学历">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { PersonInfoApi, PersonInfoVO } from '@/api/menduner/system/person'
+
+/** 人才信息 表单 */
+defineOptions({ name: 'PersonInfoForm' })
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  userId: undefined,
+  name: undefined,
+  sex: undefined,
+  avatar: undefined,
+  phone: undefined,
+  email: undefined,
+  wxCode: undefined,
+  birthday: undefined,
+  maritalStatus: undefined,
+  areaId: undefined,
+  jobType: undefined,
+  jobStatus: undefined,
+  firstWorkTime: undefined,
+  advantage: undefined,
+  expType: undefined,
+  eduType: undefined
+})
+const formRules = reactive({
+  userId: [{ required: true, message: '用户id不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await PersonInfoApi.getPersonInfo(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as PersonInfoVO
+    if (formType.value === 'create') {
+      await PersonInfoApi.createPersonInfo(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await PersonInfoApi.updatePersonInfo(data)
+      message.success(t('common.updateSuccess'))
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    userId: undefined,
+    name: undefined,
+    sex: undefined,
+    avatar: undefined,
+    phone: undefined,
+    email: undefined,
+    wxCode: undefined,
+    birthday: undefined,
+    maritalStatus: undefined,
+    areaId: undefined,
+    jobType: undefined,
+    jobStatus: undefined,
+    firstWorkTime: undefined,
+    advantage: undefined,
+    expType: undefined,
+    eduType: undefined
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 33 - 0
src/views/menduner/system/person/details/components/account.vue

@@ -0,0 +1,33 @@
+<template>
+  <div>
+    <el-descriptions class="margin-top" :column="1" border>
+      <el-descriptions-item label="用户类型">{{ info.userType === '1' ? '管理员' : '普通用户' }}</el-descriptions-item>
+      <el-descriptions-item label="账户积分">{{ info.point }}</el-descriptions-item>
+      <el-descriptions-item label="账户余额">{{ info.balance }}</el-descriptions-item>
+      <el-descriptions-item label="累计支出">{{ info.totalExpense }}</el-descriptions-item>
+      <el-descriptions-item label="累计充值">{{ info.totalRecharge }}</el-descriptions-item>
+      <el-descriptions-item label="冻结金额">{{ info.freezePrice }}</el-descriptions-item>
+      <el-descriptions-item label="创建时间">{{ formatDate(info.createTime) }}</el-descriptions-item>
+    </el-descriptions>
+  </div>
+</template>
+
+<script setup>
+/* 账户详情 */
+defineOptions({ name: 'PersonAccount'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { formatDate } from '@/utils/formatTime'
+import { DICT_TYPE } from '@/utils/dict'
+
+const props = defineProps({
+  userId: String
+})
+
+const info = ref({})
+const getInfo = async () => {
+  const data = await PersonInfoApi.getPersonAccount(props.userId)
+  const res = await PersonInfoApi.getPersonWallet(props.userId)
+  info.value = { ...data, ...res }
+}
+getInfo()
+</script>

+ 30 - 0
src/views/menduner/system/person/details/components/collect.vue

@@ -0,0 +1,30 @@
+<template>
+  <div>
+    <el-descriptions class="margin-top" :column="1" border>
+      <el-descriptions-item label="职位收藏数量">{{ info.position || 0 }}</el-descriptions-item>
+      <el-descriptions-item label="企业收藏数量">{{ info.enterprise || 0 }}</el-descriptions-item>
+    </el-descriptions>
+  </div>
+</template>
+
+<script setup>
+/* 职位、企业收藏数量 */
+defineOptions({ name: 'PersonAccount'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { formatDate } from '@/utils/formatTime'
+import { DICT_TYPE } from '@/utils/dict'
+
+const props = defineProps({
+  userId: String
+})
+
+const info = ref({
+  position: 0,
+  enterprise: 0
+})
+const getInfo = async () => {
+  info.value.position = await PersonInfoApi.getPersonJobFavoriteCount(props.userId)
+  info.value.enterprise = await PersonInfoApi.getPersonEnterpriseSubscribeCount(props.userId)
+}
+getInfo()
+</script>

+ 70 - 0
src/views/menduner/system/person/details/components/edu.vue

@@ -0,0 +1,70 @@
+<template>
+  <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
+    <el-table-column label="学校名称" align="center" prop="schoolName" />
+    <el-table-column label="专业名称" align="center" prop="major" />
+    <el-table-column label="学历" align="center" prop="educationType">
+      <template #default="scope">
+        <dict-tag :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="scope.row.educationType" />
+      </template>
+    </el-table-column>
+    <el-table-column label="学制类型" align="center" prop="educationSystemType">
+      <template #default="scope">
+        <dict-tag :type="DICT_TYPE.MENDUNER_EDUCATION_SYSTEM_TYPE" :value="scope.row.educationSystemType" />
+      </template>
+    </el-table-column>
+    <el-table-column
+      label="在校开始日期"
+      align="center"
+      prop="startTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+    <el-table-column
+      label="在校结束日期"
+      align="center"
+      prop="endTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+    <el-table-column label="在校经历" align="center" prop="content" :show-overflow-tooltip="true" />
+  </el-table>
+
+  <Pagination
+    :total="total"
+    v-model:page="queryParams.pageNo"
+    v-model:limit="queryParams.pageSize"
+    @pagination="getList"
+  />
+</template>
+
+<script setup>
+defineOptions({ name: 'PersonEduList'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps({
+  userId: String
+})
+
+const loading = ref(false)
+const tableData = ref([])
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: props.userId
+})
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonEduPage(queryParams)
+    tableData.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+getList()
+</script>

+ 74 - 0
src/views/menduner/system/person/details/components/exp.vue

@@ -0,0 +1,74 @@
+<template>
+  <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
+    <el-table-column label="企业名称" align="center" prop="enterpriseName" />
+    <el-table-column label="所属部门" align="center" prop="deptName" />
+    <el-table-column label="所属行业" align="center" prop="industryId" />
+    <el-table-column label="职位名称" align="center" prop="positionName" />
+    <el-table-column label="薪酬" align="center" prop="pay" />
+    <el-table-column label="薪酬类型" align="center" prop="payUnit">
+      <template #default="scope">
+        <dict-tag :type="DICT_TYPE.MENDUNER_PAY_TYPE" :value="scope.row.payUnit" />
+      </template>
+    </el-table-column>
+    <el-table-column label="货币类型" align="center" prop="currencyType">
+      <template #default="scope">
+        <dict-tag :type="DICT_TYPE.MENDUNER_CURRENCY_TYPE" :value="scope.row.currencyType" />
+      </template>
+    </el-table-column>
+    <el-table-column
+      label="工作开始日期"
+      align="center"
+      prop="startTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+    <el-table-column
+      label="工作结束日期"
+      align="center"
+      prop="endTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+    <el-table-column label="业绩" align="center" prop="achievement" :show-overflow-tooltip="true" />
+    <el-table-column label="工作内容" align="center" prop="content" :show-overflow-tooltip="true" />
+  </el-table>
+
+  <Pagination
+    :total="total"
+    v-model:page="queryParams.pageNo"
+    v-model:limit="queryParams.pageSize"
+    @pagination="getList"
+  />
+</template>
+
+<script setup>
+defineOptions({ name: 'PersonExpList'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps({
+  userId: String
+})
+
+const loading = ref(false)
+const tableData = ref([])
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: props.userId
+})
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonExpPage(queryParams)
+    tableData.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+getList()
+</script>

+ 51 - 0
src/views/menduner/system/person/details/components/info.vue

@@ -0,0 +1,51 @@
+<template>
+  <div>
+    <el-descriptions class="margin-top" :column="2" border>
+      <el-descriptions-item label="用户头像">
+        <el-image v-if="info.avatar" style="width: 100px; height: 100px" :src="info.avatar" fit="contain" hide-on-click-modal :preview-src-list="[info.avatar]"/>
+      </el-descriptions-item>
+      <el-descriptions-item label="用户名">{{ info.name }}</el-descriptions-item>
+      <el-descriptions-item label="性别">
+        <dict-tag v-if="info.sex !== '0'" :type="DICT_TYPE.MENDUNER_SEX" :value="info.sex" />
+      </el-descriptions-item>
+      <el-descriptions-item label="联系电话">{{ info.phone }}</el-descriptions-item>
+      <el-descriptions-item label="邮箱">{{ info.email }}</el-descriptions-item>
+      <el-descriptions-item label="出生日期">{{ formatDate(info.birthday, 'YYYY-MM-DD') }}</el-descriptions-item>
+      <el-descriptions-item label="首次工作时间">{{ formatDate(info.firstWorkTime, 'YYYY-MM-DD') }}</el-descriptions-item>
+      <el-descriptions-item label="婚姻状况">
+        <dict-tag :type="DICT_TYPE.MENDUNER_MARITAL_STATUS" :value="info.maritalStatus" />
+      </el-descriptions-item>
+      <!-- <el-descriptions-item label="现居住地">{{ info.areaId }}</el-descriptions-item> -->
+      <el-descriptions-item label="学历">
+        <dict-tag :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="info.eduType" />
+      </el-descriptions-item>
+      <el-descriptions-item label="	工作经验">
+        <dict-tag :type="DICT_TYPE.MENDUNER_EXP_TYPE" :value="info.expType" />
+      </el-descriptions-item>
+      <el-descriptions-item label="求职类型">
+        <dict-tag :type="DICT_TYPE.MENDUNER_JOB_TYPE" :value="info.jobType" />
+      </el-descriptions-item>
+      <el-descriptions-item label="求职状态">
+        <dict-tag :type="DICT_TYPE.MENDUNER_JOB_STATUS" :value="info.jobStatus" />
+      </el-descriptions-item>
+    </el-descriptions>
+  </div>
+</template>
+
+<script setup>
+defineOptions({ name: 'EnterpriseDetailsInfo'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { formatDate } from '@/utils/formatTime'
+import { DICT_TYPE } from '@/utils/dict'
+
+const props = defineProps({
+  id: String
+})
+
+const info = ref({})
+const getInfo = async () => {
+  const data = await PersonInfoApi.getPersonDetails(props.id)
+  info.value = data
+}
+getInfo()
+</script>

+ 61 - 0
src/views/menduner/system/person/details/components/jobIntention.vue

@@ -0,0 +1,61 @@
+<template>
+  <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
+    <el-table-column label="期望职位" align="center" prop="positionId" />
+    <el-table-column label="期望行业" align="center" prop="industryIdList" />
+    <el-table-column label="薪酬最低要求" align="center" prop="payFrom" />
+    <el-table-column label="薪酬最高要求" align="center" prop="payTo" />
+    <el-table-column label="求职类型" align="center" prop="jobType">
+      <template #default="scope">
+        <dict-tag :type="DICT_TYPE.MENDUNER_JOB_TYPE" :value="scope.row.jobType" />
+      </template>
+    </el-table-column>
+    <el-table-column label="工作城市" align="center" prop="workAreaId" />
+    <el-table-column label="其它感兴趣城市" align="center" prop="interestedAreaIdList" />
+    <el-table-column
+      label="创建时间"
+      align="center"
+      prop="createTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+  </el-table>
+
+  <Pagination
+    :total="total"
+    v-model:page="queryParams.pageNo"
+    v-model:limit="queryParams.pageSize"
+    @pagination="getList"
+  />
+</template>
+
+<script setup>
+defineOptions({ name: 'PersonJobIntentionList'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps({
+  userId: String
+})
+
+const loading = ref(false)
+const tableData = ref([])
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: props.userId
+})
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonJobIntentionPage(queryParams)
+    tableData.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+getList()
+</script>

+ 55 - 0
src/views/menduner/system/person/details/components/pointsChange.vue

@@ -0,0 +1,55 @@
+<template>
+  <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
+    <el-table-column label="标题" align="center" prop="title" />
+    <el-table-column label="描述" align="center" prop="description" />
+    <el-table-column label="获得积分点" align="center" prop="point" />
+    <el-table-column label="剩余点数" align="center" prop="totalPoint" />
+    <el-table-column
+      label="发生事件"
+      align="center"
+      prop="createTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+  </el-table>
+
+  <Pagination
+    :total="total"
+    v-model:page="queryParams.pageNo"
+    v-model:limit="queryParams.pageSize"
+    @pagination="getList"
+  />
+</template>
+
+<script setup>
+/* 积分变动记录 */
+defineOptions({ name: 'PersonPointsChangeList'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps({
+  userId: String
+})
+
+const loading = ref(false)
+const tableData = ref([])
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: props.userId
+})
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonAccountRecordPage(queryParams)
+    tableData.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+getList()
+</script>

+ 59 - 0
src/views/menduner/system/person/details/components/project.vue

@@ -0,0 +1,59 @@
+<template>
+  <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
+    <el-table-column label="项目名称" align="center" prop="name" />
+    <el-table-column
+      label="项目开始日期"
+      align="center"
+      prop="startTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+    <el-table-column
+      label="项目结束日期"
+      align="center"
+      prop="endTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+    <el-table-column label="描述内容" align="center" prop="content" :show-overflow-tooltip="true" />
+  </el-table>
+
+  <Pagination
+    :total="total"
+    v-model:page="queryParams.pageNo"
+    v-model:limit="queryParams.pageSize"
+    @pagination="getList"
+  />
+</template>
+
+<script setup>
+defineOptions({ name: 'PersonProjectList'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps({
+  userId: String
+})
+
+const loading = ref(false)
+const tableData = ref([])
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: props.userId
+})
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonProjectPage(queryParams)
+    tableData.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+getList()
+</script>

+ 76 - 0
src/views/menduner/system/person/details/components/rechargeOrder.vue

@@ -0,0 +1,76 @@
+<template>
+  <el-table v-loading="loading" :data="tableData" :stripe="true" class="m-t-20px">
+    <el-table-column label="充值点数" align="center" prop="id">
+      <template #default="scope">
+        {{ payCalculation(scope.row.payPrice, true) }}
+      </template>
+    </el-table-column>
+    <el-table-column label="支付金额" align="center" prop="payPrice">
+      <template #default="scope">
+        {{ payCalculation(scope.row.payPrice) }}
+      </template>
+    </el-table-column>
+    <el-table-column label="支付渠道" align="center" prop="payChannelName" />
+    <el-table-column label="支付订单编号" align="center" prop="payOrderId" />
+    <el-table-column label="支付成功的外部订单号" align="center" prop="payOrderChannelOrderNo" />
+    <el-table-column label="是否已支付" align="center" prop="payStatus">
+      <template #default="scope">
+        {{ scope.row.payStatus ? "已支付" : "未支付"}}
+      </template>
+    </el-table-column>
+    <el-table-column
+      label="订单支付时间"
+      align="center"
+      prop="payTime"
+      :formatter="dateFormatter"
+      width="180px"
+    />
+  </el-table>
+
+  <Pagination
+    :total="total"
+    v-model:page="queryParams.pageNo"
+    v-model:limit="queryParams.pageSize"
+    @pagination="getList"
+  />
+</template>
+
+<script setup>
+/* 充值订单 */
+defineOptions({ name: 'PersonRechargeOrderList'})
+import { PersonInfoApi } from '@/api/menduner/system/person'
+import { DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps({
+  userId: String
+})
+
+const loading = ref(false)
+const tableData = ref([])
+const total = ref(0)
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: props.userId
+})
+
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonWalletRechargePage(queryParams)
+    tableData.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+getList()
+
+const payCalculation = (count, status) => {
+  if ((count - 0) === 0) return 0
+  if (!count) return ''
+  const Magnification = 1 / 100 
+  return status ? 10 * ((count - 0) * Magnification).toFixed(2) : ((count - 0) * Magnification).toFixed(2)
+}
+</script>

+ 85 - 0
src/views/menduner/system/person/details/index.vue

@@ -0,0 +1,85 @@
+<template>
+  <div>
+    <el-row :gutter="10">
+      <el-col :span="12">
+        <el-card shadow="never">
+          <template #header>
+            <CardTitle title="人才详情" />
+          </template>
+          <Info :id="id"/>
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card shadow="never">
+          <template #header>
+            <CardTitle title="账户信息" />
+          </template>
+          <Account :user-id="userId" />
+        </el-card>
+      </el-col>
+      <el-col :span="6">
+        <el-card shadow="never">
+          <template #header>
+            <CardTitle title="职位收藏、企业收藏数" />
+          </template>
+          <Collect :user-id="userId" />
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-row class="m-t-20px">
+      <el-col :span="24">
+        <el-card shadow="never">
+          <el-tabs>
+            <el-tab-pane label="教育经历">
+              <Edu :user-id="userId" />
+            </el-tab-pane>
+            <el-tab-pane label="工作经历">
+              <Exp :user-id="userId" />
+            </el-tab-pane>
+            <el-tab-pane label="项目经历">
+              <Project :user-id="userId" />
+            </el-tab-pane>
+            <el-tab-pane label="求职意向">
+              <JobIntention :user-id="userId" />
+            </el-tab-pane>
+            <el-tab-pane label="钱包充值记录">
+              <RechargeOrder :user-id="userId" />
+            </el-tab-pane>
+            <el-tab-pane label="积分变动记录">
+              <PointsChange :user-id="userId" />
+            </el-tab-pane>
+          </el-tabs>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+defineOptions({ name: 'PersonDetails'})
+import { useTagsViewStore } from '@/store/modules/tagsView'
+import { ElMessage } from 'element-plus'
+import Info from './components/info.vue'
+import Account from './components/account.vue'
+import Edu from './components/edu.vue'
+import Exp from './components/exp.vue'
+import Project from './components/project.vue'
+import JobIntention from './components/jobIntention.vue'
+import RechargeOrder from './components/rechargeOrder.vue'
+import PointsChange from './components/pointsChange.vue'
+import Collect from './components/collect.vue'
+
+/** 初始化 */
+const { currentRoute } = useRouter() // 路由
+const { delView } = useTagsViewStore() // 视图操作
+const route = useRoute()
+const { id, userId } = route.query
+onMounted(() => {
+  if (!id || !userId) {
+    ElMessage.warning('参数错误,用户编号不能为空!')
+    delView(unref(currentRoute))
+    return
+  }
+})
+</script>

+ 301 - 0
src/views/menduner/system/person/index.vue

@@ -0,0 +1,301 @@
+<template>
+  <ContentWrap>
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="120px"
+    >
+      <el-form-item label="用户id" prop="userId">
+        <el-input
+          v-model="queryParams.userId"
+          placeholder="请输入用户id"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="真实姓名" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入真实姓名"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="用户性别" prop="sex">
+        <el-select
+          v-model="queryParams.sex"
+          placeholder="请选择用户性别"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MENDUNER_SEX)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="联系手机号" prop="phone">
+        <el-input
+          v-model="queryParams.phone"
+          placeholder="请输入联系手机号"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="用户邮箱" prop="email">
+        <el-input
+          v-model="queryParams.email"
+          placeholder="请输入用户邮箱"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="工作经验" prop="expType">
+        <el-select
+          v-model="queryParams.expType"
+          placeholder="请选择工作经验"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MENDUNER_EXP_TYPE)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="学历" prop="eduType">
+        <el-select
+          v-model="queryParams.eduType"
+          placeholder="请选择学历"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.MENDUNER_EDUCATION_TYPE)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['menduner:system:person-info:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
+        <el-button
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['menduner:system:person-info:export']"
+        >
+          <Icon icon="ep:download" class="mr-5px" /> 导出
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="用户id" align="center" prop="userId" />
+      <el-table-column label="真实姓名" align="center" prop="name" />
+      <el-table-column label="用户性别" align="center" prop="sex">
+        <template #default="scope">
+          <dict-tag v-if="scope.row.sex !== '0'" :type="DICT_TYPE.MENDUNER_SEX" :value="scope.row.sex" />
+          <span v-else></span>
+        </template>
+      </el-table-column>
+      <el-table-column label="头像地址" align="center" prop="avatar">
+        <template #default="scope">
+          <el-image v-if="scope.row.avatar" style="width: 60px; height: 60px" :src="scope.row.avatar" fit="contain" />
+        </template>
+      </el-table-column>
+      <el-table-column label="联系手机号" align="center" prop="phone" />
+      <el-table-column label="用户邮箱" align="center" prop="email" />
+      <el-table-column label="工作经验" align="center" prop="expType">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.MENDUNER_EXP_TYPE" :value="scope.row.expType" />
+        </template>
+      </el-table-column>
+      <el-table-column label="学历" align="center" prop="expType">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.MENDUNER_EDUCATION_TYPE" :value="scope.row.eduType" />
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <!-- <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['menduner:system:person-info:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['menduner:system:person-info:delete']"
+          >
+            删除
+          </el-button> -->
+          <el-button
+            link
+            type="primary"
+            @click="openDetail(scope.row.id, scope.row.userId)"
+          >
+            详情
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <PersonInfoForm ref="formRef" @success="getList" />
+</template>
+
+<script setup lang="ts">
+// import { dateFormatter } from '@/utils/formatTime'
+import download from '@/utils/download'
+import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
+import { PersonInfoApi, PersonInfoVO } from '@/api/menduner/system/person'
+import PersonInfoForm from './PersonInfoForm.vue'
+
+/** 人才信息 列表 */
+defineOptions({ name: 'PersonInfo' })
+
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
+
+const loading = ref(true) // 列表的加载中
+const list = ref<PersonInfoVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  userId: undefined,
+  name: undefined,
+  sex: undefined,
+  phone: undefined,
+  email: undefined,
+  wxCode: undefined,
+  maritalStatus: undefined,
+  areaId: undefined,
+  jobType: undefined,
+  jobStatus: undefined,
+  expType: undefined,
+  eduType: undefined,
+  createTime: []
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await PersonInfoApi.getPersonInfoPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 打开企业详情 */
+const { push } = useRouter()
+const openDetail = (id: string, userId: string) => {
+  push({ name: 'PersonDetail', query: { id, userId } })
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await PersonInfoApi.deletePersonInfo(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await PersonInfoApi.exportPersonInfo(queryParams)
+    download.excel(data, '人才信息.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
+  }
+}
+
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
+</script>