|
|
@@ -10,84 +10,36 @@
|
|
|
<div class="register">
|
|
|
<div class="form">
|
|
|
<van-row class="pl10 pr10 pt10">
|
|
|
- <van-button
|
|
|
- type="success"
|
|
|
- @click="changeType('10')"
|
|
|
- >
|
|
|
+ <van-button type="success" @click="changeType('10')">
|
|
|
注册课题组成员
|
|
|
</van-button>
|
|
|
- <van-button
|
|
|
- type="primary"
|
|
|
- @click="changeType('20')"
|
|
|
- >
|
|
|
+ <van-button type="primary" @click="changeType('20')">
|
|
|
注册课题组负责人
|
|
|
</van-button>
|
|
|
</van-row>
|
|
|
- <van-steps
|
|
|
- :active="state.active"
|
|
|
- class="pl20 pr20 pt10"
|
|
|
- >
|
|
|
+ <van-steps :active="state.active" class="pl20 pr20 pt10">
|
|
|
<van-step>登录信息</van-step>
|
|
|
<van-step>个人信息</van-step>
|
|
|
<van-step v-if="state.form.registerType == '20'">项目信息</van-step>
|
|
|
</van-steps>
|
|
|
- <van-form
|
|
|
- ref="loginInfoRef"
|
|
|
- v-show="state.active == 0"
|
|
|
- required="auto"
|
|
|
- >
|
|
|
+ <van-form ref="loginInfoRef" v-show="state.active == 0" required="auto">
|
|
|
<van-cell-group inset>
|
|
|
- <van-field
|
|
|
- v-model="state.form.userName"
|
|
|
- label="登录账号"
|
|
|
- placeholder="登录账号"
|
|
|
- @blur="checkUserNamePhoneExists('userName')"
|
|
|
- :rules="[{ required: true, message: '请填写登录账号' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.password"
|
|
|
- type="password"
|
|
|
- label="密码"
|
|
|
- placeholder="密码"
|
|
|
- :rules="[{ required: true, validator: checkPassword, }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.confirmPassword"
|
|
|
- type="password"
|
|
|
- label="确认密码"
|
|
|
- placeholder="确认密码"
|
|
|
- :rules="[{ required: true, validator: confirmPasswordSame, message: '两次输入的密码不一致' }]"
|
|
|
- />
|
|
|
+ <van-field v-model="state.form.userName" label="登录账号" placeholder="登录账号"
|
|
|
+ @blur="checkUserNamePhoneExists('userName')" :rules="[{ required: true, message: '请填写登录账号' }]" />
|
|
|
+ <van-field v-model="state.form.password" type="password" label="密码" placeholder="密码"
|
|
|
+ :rules="[{ required: true, validator: checkPassword, }]" />
|
|
|
+ <van-field v-model="state.form.confirmPassword" type="password" label="确认密码" placeholder="确认密码"
|
|
|
+ :rules="[{ required: true, validator: confirmPasswordSame, message: '两次输入的密码不一致' }]" />
|
|
|
</van-cell-group>
|
|
|
</van-form>
|
|
|
- <van-form
|
|
|
- ref="personInfoRef"
|
|
|
- v-show="state.active == 1"
|
|
|
- required="auto"
|
|
|
- >
|
|
|
+ <van-form ref="personInfoRef" v-show="state.active == 1" required="auto">
|
|
|
<van-cell-group inset>
|
|
|
- <van-field
|
|
|
- v-model="state.form.nickName"
|
|
|
- label="姓名"
|
|
|
- placeholder="姓名"
|
|
|
- :rules="[{ required: true, message: '请填写姓名' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- label="性别"
|
|
|
- :rules="[{ required: false }]"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.nickName" label="姓名" placeholder="姓名"
|
|
|
+ :rules="[{ required: true, message: '请填写姓名' }]" />
|
|
|
+ <van-field label="性别" :rules="[{ required: false }]">
|
|
|
<template #input>
|
|
|
- <van-radio-group
|
|
|
- v-model="state.form.sex"
|
|
|
- label="性别"
|
|
|
- placeholder="性别"
|
|
|
- direction="horizontal"
|
|
|
- >
|
|
|
- <van-radio
|
|
|
- v-for="item in userSexList"
|
|
|
- :name="item.dictValue"
|
|
|
- :key="item.dictValue"
|
|
|
- >
|
|
|
+ <van-radio-group v-model="state.form.sex" label="性别" placeholder="性别" direction="horizontal">
|
|
|
+ <van-radio v-for="item in userSexList" :name="item.dictValue" :key="item.dictValue">
|
|
|
{{ item.dictLabel }}
|
|
|
</van-radio>
|
|
|
</van-radio-group>
|
|
|
@@ -96,261 +48,151 @@
|
|
|
<van-field>
|
|
|
<template #label>
|
|
|
<span>用户类型</span>
|
|
|
- <el-tooltip
|
|
|
- class="box-item"
|
|
|
- effect="dark"
|
|
|
- placement="top"
|
|
|
- append-to="body"
|
|
|
- >
|
|
|
+ <el-tooltip class="box-item" effect="dark" placement="top" append-to="body">
|
|
|
<template #content>
|
|
|
- <div
|
|
|
- v-for="item in UserTypeTooltip"
|
|
|
- :key="item"
|
|
|
- >
|
|
|
+ <div v-for="item in UserTypeTooltip" :key="item">
|
|
|
{{ item }}
|
|
|
</div>
|
|
|
</template>
|
|
|
- <el-icon style="margin-left: 10px;"><QuestionFilled /></el-icon>
|
|
|
+ <el-icon style="margin-left: 10px;">
|
|
|
+ <QuestionFilled />
|
|
|
+ </el-icon>
|
|
|
</el-tooltip>
|
|
|
</template>
|
|
|
<template #input>
|
|
|
- <van-radio-group
|
|
|
- v-model="state.form.userType"
|
|
|
- label="用户类型"
|
|
|
- placeholder="用户类型"
|
|
|
- direction="horizontal"
|
|
|
- >
|
|
|
- <van-radio
|
|
|
- v-for="item in userTypeList"
|
|
|
- :name="item.dictValue"
|
|
|
- :key="item.dictValue"
|
|
|
- >
|
|
|
+ <van-radio-group v-model="state.form.userType" label="用户类型" placeholder="用户类型" direction="horizontal">
|
|
|
+ <van-radio v-for="item in userTypeList" :name="item.dictValue" :key="item.dictValue">
|
|
|
{{ item.dictLabel }}
|
|
|
</van-radio>
|
|
|
</van-radio-group>
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.deptName"
|
|
|
- is-link
|
|
|
- readonly
|
|
|
- label="组织部门"
|
|
|
- placeholder="组织部门"
|
|
|
- @click="showDeptPickerHandler"
|
|
|
- :rules="[{ required: true, message: '请选择组织部门' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-if="needInputDeptInfo"
|
|
|
- v-model="state.form.deptDescribe"
|
|
|
- label="部门描述"
|
|
|
- placeholder="部门描述"
|
|
|
- :rules="[{ required: true, message: '请填写部门描述' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.phone"
|
|
|
- type="tel"
|
|
|
- label="手机号"
|
|
|
- placeholder="手机号"
|
|
|
- @blur="checkUserNamePhoneExists('phone')"
|
|
|
- :rules="[{ required: true, message: '请填写手机号' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.email"
|
|
|
- label="邮箱"
|
|
|
- placeholder="邮箱"
|
|
|
- :rules="[{ required: true, message: '请填写邮箱' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- label="证件类型"
|
|
|
- :rules="[{ required: true, message: '请选择证件类型' }]"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.deptName" is-link readonly label="组织部门" placeholder="组织部门"
|
|
|
+ @click="showDeptPickerHandler" :rules="[{ required: true, message: '请选择组织部门' }]" />
|
|
|
+ <van-field v-if="needInputDeptInfo" v-model="state.form.deptDescribe" label="部门描述" placeholder="部门描述"
|
|
|
+ :rules="[{ required: true, message: '请填写部门描述' }]" />
|
|
|
+ <van-field v-model="state.form.phone" type="tel" label="手机号" placeholder="手机号"
|
|
|
+ @blur="checkUserNamePhoneExists('phone')" :rules="[{ required: true, message: '请填写手机号' }]" />
|
|
|
+ <van-field v-model="state.form.email" label="邮箱" placeholder="邮箱"
|
|
|
+ :rules="[{ required: true, message: '请填写邮箱' }]" />
|
|
|
+ <van-field label="证件类型" :rules="[{ required: true, message: '请选择证件类型' }]">
|
|
|
<template #input>
|
|
|
- <van-radio-group
|
|
|
- disabled
|
|
|
- v-model="state.form.idType"
|
|
|
- label="证件类型"
|
|
|
- placeholder="证件类型"
|
|
|
- direction="horizontal"
|
|
|
- >
|
|
|
- <van-radio
|
|
|
- v-for="item in userCertList"
|
|
|
- :name="item.dictValue"
|
|
|
- :key="item.id"
|
|
|
- >
|
|
|
+ <van-radio-group disabled v-model="state.form.idType" label="证件类型" placeholder="证件类型"
|
|
|
+ direction="horizontal">
|
|
|
+ <van-radio v-for="item in userCertList" :name="item.dictValue" :key="item.id">
|
|
|
{{ item.dictLabel }}
|
|
|
</van-radio>
|
|
|
</van-radio-group>
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.idCode"
|
|
|
- label="证件号"
|
|
|
- placeholder="证件号"
|
|
|
- :rules="[{ required: true, message: '请填写证件号' }]"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.projectGroupName"
|
|
|
- v-if="state.form.registerType === '20'"
|
|
|
- label="课题组"
|
|
|
- placeholder="课题组"
|
|
|
- :rules="[{ required: true, message: '请填写课题组' }]"
|
|
|
- />
|
|
|
+ <van-field v-model="state.form.idCode" label="证件号" placeholder="证件号"
|
|
|
+ :rules="[{ required: true, message: '请填写证件号' }]" />
|
|
|
+ <van-field v-model="state.form.projectGroupName" v-if="state.form.registerType === '20'" label="课题组"
|
|
|
+ placeholder="课题组" :rules="[{ required: true, message: '请填写课题组' }]" />
|
|
|
<template v-else>
|
|
|
- <van-field
|
|
|
- :disabled="!state.form.deptId"
|
|
|
- v-model="state.form.projectGroupName"
|
|
|
- is-link
|
|
|
- readonly
|
|
|
- label="课题组"
|
|
|
- placeholder="课题组"
|
|
|
- :rules="[{ required: true, message: '请填写课题组' }]"
|
|
|
- @click="showPjtPicker = true"
|
|
|
- />
|
|
|
+ <van-field :disabled="!state.form.deptId" v-model="state.form.projectGroupName" is-link readonly label="课题组"
|
|
|
+ placeholder="课题组" :rules="[{ required: true, message: '请填写课题组' }]" @click="showPjtPicker = true" />
|
|
|
</template>
|
|
|
</van-cell-group>
|
|
|
</van-form>
|
|
|
- <van-form
|
|
|
- ref="projectInfoRef"
|
|
|
- v-show="state.active == 2"
|
|
|
- required="auto"
|
|
|
- >
|
|
|
+ <van-form ref="projectInfoRef" v-show="state.active == 2" required="auto">
|
|
|
<van-cell-group inset>
|
|
|
- <van-field>
|
|
|
- <template #input>
|
|
|
- <div class="w100">
|
|
|
- <van-button
|
|
|
- type="primary"
|
|
|
- block
|
|
|
- @click="addProject"
|
|
|
- >
|
|
|
- 新增
|
|
|
+ <div class="project-list-container">
|
|
|
+ <van-button type="primary" block @click="addProject" class="add-project-btn">
|
|
|
+ 新增项目
|
|
|
+ </van-button>
|
|
|
+ <div v-if="state.form.projectList.length === 0" class="empty-project-tip">
|
|
|
+ 请至少添加一个项目
|
|
|
+ </div>
|
|
|
+ <div v-for="(item, index) in state.form.projectList" :key="index" class="project-card">
|
|
|
+ <div class="project-card-header">
|
|
|
+ <span class="project-card-title">项目 {{ index + 1 }}</span>
|
|
|
+ <van-button
|
|
|
+ v-if="state.form.projectList.length > 1"
|
|
|
+ size="mini"
|
|
|
+ type="danger"
|
|
|
+ plain
|
|
|
+ @click="delProjectItem(index)"
|
|
|
+ class="delete-btn">
|
|
|
+ 删除
|
|
|
</van-button>
|
|
|
- <template
|
|
|
- v-for="(item, index) in state.form.projectList"
|
|
|
- :key="index"
|
|
|
- >
|
|
|
- <van-field
|
|
|
- v-model="item.projectName"
|
|
|
- placeholder="项目名称"
|
|
|
- class="mt10"
|
|
|
- ></van-field>
|
|
|
- <van-field
|
|
|
- v-model="item.projectTypeName"
|
|
|
- is-link
|
|
|
- readonly
|
|
|
- label="项目类型"
|
|
|
- placeholder="项目类型"
|
|
|
- @click="openPjtType(item, index)"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="item.projectSource"
|
|
|
- placeholder="项目来源"
|
|
|
- ></van-field>
|
|
|
- <van-button
|
|
|
- style="height: 30px"
|
|
|
- type="danger"
|
|
|
- icon="el-icon-delete"
|
|
|
- @click="delProjectItem(index)"
|
|
|
- >
|
|
|
- 删除
|
|
|
- </van-button>
|
|
|
- </template>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- </van-field>
|
|
|
+ <div class="project-card-body">
|
|
|
+ <van-field
|
|
|
+ v-model="item.projectName"
|
|
|
+ label="项目名称"
|
|
|
+ placeholder="请输入项目名称"
|
|
|
+ :rules="[{ required: true, message: '请输入项目名称' }]"
|
|
|
+ class="project-field">
|
|
|
+ </van-field>
|
|
|
+ <van-field
|
|
|
+ v-model="item.projectTypeName"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ label="项目类型"
|
|
|
+ placeholder="请选择项目类型"
|
|
|
+ @click="openPjtType(item, index)"
|
|
|
+ :rules="[{ required: true, message: '请选择项目类型' }]"
|
|
|
+ class="project-field">
|
|
|
+ </van-field>
|
|
|
+ <van-field
|
|
|
+ v-model="item.projectSource"
|
|
|
+ label="项目来源"
|
|
|
+ placeholder="请输入项目来源"
|
|
|
+ :rules="[{ required: true, message: '请输入项目来源' }]"
|
|
|
+ class="project-field">
|
|
|
+ </van-field>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</van-cell-group>
|
|
|
</van-form>
|
|
|
</div>
|
|
|
<footer>
|
|
|
- <van-button
|
|
|
- v-if="state.active > 0"
|
|
|
- @click="preStep"
|
|
|
- >
|
|
|
+ <van-button v-if="state.active > 0" @click="preStep">
|
|
|
上一步
|
|
|
</van-button>
|
|
|
- <van-button
|
|
|
- v-if="state.active < (state.form.registerType == '10' ? 1 : 2)"
|
|
|
- type="primary"
|
|
|
- class="ml10"
|
|
|
- @click="nextStep"
|
|
|
- >
|
|
|
+ <van-button v-if="state.active < (state.form.registerType == '10' ? 1 : 2)" type="primary" class="ml10"
|
|
|
+ @click="nextStep">
|
|
|
下一步
|
|
|
</van-button>
|
|
|
- <van-button
|
|
|
- v-if="
|
|
|
- (state.form.registerType == '10' && state.active === 1) ||
|
|
|
- (state.form.registerType == '20' && state.active === 2)
|
|
|
- "
|
|
|
- @click="onRegister"
|
|
|
- type="primary"
|
|
|
- class="ml10"
|
|
|
- >
|
|
|
+ <van-button v-if="
|
|
|
+ (state.form.registerType == '10' && state.active === 1) ||
|
|
|
+ (state.form.registerType == '20' && state.active === 2)
|
|
|
+ " @click="onRegister" type="primary" class="ml10">
|
|
|
提交
|
|
|
</van-button>
|
|
|
</footer>
|
|
|
<!-- 部门选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showDeptPicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
+ <van-popup v-model:show="showDeptPicker" position="bottom">
|
|
|
<div class="cascade-picker">
|
|
|
<div class="cascade-header">
|
|
|
<span>请选择部门</span>
|
|
|
- <van-icon
|
|
|
- name="cross"
|
|
|
- @click="showDeptPicker = false"
|
|
|
- />
|
|
|
+ <van-icon name="cross" @click="showDeptPicker = false" />
|
|
|
</div>
|
|
|
<div class="cascade-content">
|
|
|
<!-- 第一级 -->
|
|
|
<div class="cascade-column">
|
|
|
- <div
|
|
|
- v-for="item in cascadeData.level1"
|
|
|
- :key="item.id"
|
|
|
- class="cascade-item"
|
|
|
- :class="{ active: selectedLevel1?.id === item.id }"
|
|
|
- @click="selectLevel1(item)"
|
|
|
- >
|
|
|
+ <div v-for="item in cascadeData.level1" :key="item.id" class="cascade-item"
|
|
|
+ :class="{ active: selectedLevel1?.id === item.id }" @click="selectLevel1(item)">
|
|
|
<span>{{ item.deptName }}{{ item.children?.length ? `(${item.children.length})` : '' }}</span>
|
|
|
- <van-icon
|
|
|
- v-if="item.children?.length"
|
|
|
- name="arrow"
|
|
|
- />
|
|
|
+ <van-icon v-if="item.children?.length" name="arrow" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 第二级 -->
|
|
|
- <div
|
|
|
- v-if="cascadeData.level2.length"
|
|
|
- class="cascade-column"
|
|
|
- >
|
|
|
- <div
|
|
|
- v-for="item in cascadeData.level2"
|
|
|
- :key="item.id"
|
|
|
- class="cascade-item"
|
|
|
- :class="{ active: selectedLevel2?.id === item.id }"
|
|
|
- @click="selectLevel2(item)"
|
|
|
- >
|
|
|
+ <div v-if="cascadeData.level2.length" class="cascade-column">
|
|
|
+ <div v-for="item in cascadeData.level2" :key="item.id" class="cascade-item"
|
|
|
+ :class="{ active: selectedLevel2?.id === item.id }" @click="selectLevel2(item)">
|
|
|
<span>{{ item.deptName }}{{ item.children?.length ? `(${item.children.length})` : '' }}</span>
|
|
|
- <van-icon
|
|
|
- v-if="item.children?.length"
|
|
|
- name="arrow"
|
|
|
- />
|
|
|
+ <van-icon v-if="item.children?.length" name="arrow" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 第三级 -->
|
|
|
- <div
|
|
|
- v-if="cascadeData.level3.length"
|
|
|
- class="cascade-column"
|
|
|
- >
|
|
|
- <div
|
|
|
- v-for="item in cascadeData.level3"
|
|
|
- :key="item.id"
|
|
|
- class="cascade-item"
|
|
|
- :class="{ active: selectedLevel3?.id === item.id }"
|
|
|
- @click="selectLevel3(item)"
|
|
|
- >
|
|
|
+ <div v-if="cascadeData.level3.length" class="cascade-column">
|
|
|
+ <div v-for="item in cascadeData.level3" :key="item.id" class="cascade-item"
|
|
|
+ :class="{ active: selectedLevel3?.id === item.id }" @click="selectLevel3(item)">
|
|
|
<span>{{ item.deptName }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -358,488 +200,600 @@
|
|
|
|
|
|
<div class="cascade-footer">
|
|
|
<van-button @click="showDeptPicker = false">取消</van-button>
|
|
|
- <van-button
|
|
|
- type="primary"
|
|
|
- @click="confirmCascadeSelection"
|
|
|
- >
|
|
|
+ <van-button type="primary" @click="confirmCascadeSelection">
|
|
|
确定
|
|
|
</van-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</van-popup>
|
|
|
<!-- 课题组选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showPjtPicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker
|
|
|
- :columns="pjtList"
|
|
|
- :columns-field-names="{ text: 'pgName', value: 'id' }"
|
|
|
- @confirm="onPjtPicker"
|
|
|
- @cancel="showPjtPicker = false"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="showPjtPicker" position="bottom">
|
|
|
+ <van-picker :columns="pjtList" :columns-field-names="{ text: 'pgName', value: 'id' }" @confirm="onPjtPicker"
|
|
|
+ @cancel="showPjtPicker = false" />
|
|
|
</van-popup>
|
|
|
<!-- 所在时间 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showPjtDatePicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker-group
|
|
|
- title="预约日期"
|
|
|
- :tabs="['开始日期', '结束日期']"
|
|
|
- next-step-text="下一步"
|
|
|
- @confirm="onPjtDatePicker"
|
|
|
- >
|
|
|
+ <van-popup v-model:show="showPjtDatePicker" position="bottom">
|
|
|
+ <van-picker-group title="预约日期" :tabs="['开始日期', '结束日期']" next-step-text="下一步" @confirm="onPjtDatePicker">
|
|
|
<van-date-picker v-model="state.form.startDate" />
|
|
|
<van-date-picker v-model="state.form.endDate" />
|
|
|
</van-picker-group>
|
|
|
</van-popup>
|
|
|
<!-- 项目类型 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showPjtTypePicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker
|
|
|
- :columns="pjtTypeList"
|
|
|
- :columns-field-names="{ text: 'dictLabel', value: 'dictValue' }"
|
|
|
- @confirm="onPjtTypePicker"
|
|
|
- @cancel="showPjtTypePicker = false"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="showPjtTypePicker" position="bottom">
|
|
|
+ <van-picker :columns="pjtTypeList" :columns-field-names="{ text: 'dictLabel', value: 'dictValue' }"
|
|
|
+ @confirm="onPjtTypePicker" @cancel="showPjtTypePicker = false" />
|
|
|
</van-popup>
|
|
|
- <van-notify
|
|
|
- v-model:show="show"
|
|
|
- type="danger"
|
|
|
- >
|
|
|
+ <van-notify v-model:show="show" type="danger">
|
|
|
<span>操作失败</span>
|
|
|
</van-notify>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script name="register" lang="ts" setup>
|
|
|
- import { onMounted, reactive, ref, watch } from 'vue'
|
|
|
- import to from 'await-to-js'
|
|
|
- import { useLoginApi } from '/@/api/login/index'
|
|
|
- import crypto from 'sm-crypto'
|
|
|
- import { useDictApi } from '/@/api/system/dict'
|
|
|
- import { useProApi } from '/@/api/project'
|
|
|
- import { useDeptApi } from '/@/api/system/dept'
|
|
|
- import { useRouter, useRoute } from 'vue-router'
|
|
|
- import { showNotify } from 'vant'
|
|
|
-
|
|
|
- import { UserTypeTooltip } from '/@/constants/pageConstants'
|
|
|
- import { isPasswordValid } from '/@/utils/stringUtils'
|
|
|
-
|
|
|
- const sm3 = crypto.sm3
|
|
|
- const loginApi = useLoginApi()
|
|
|
- const router = useRouter()
|
|
|
- const dictApi = useDictApi()
|
|
|
- const proApi = useProApi()
|
|
|
- const deptApi = useDeptApi()
|
|
|
- const loginInfoRef = ref()
|
|
|
- const personInfoRef = ref()
|
|
|
- const projectInfoRef = ref()
|
|
|
- const showDeptPicker = ref(false)
|
|
|
- const showPjtPicker = ref(false)
|
|
|
- const showPjtDatePicker = ref(false)
|
|
|
- const showPjtTypePicker = ref(false)
|
|
|
- const show = ref(false)
|
|
|
- const pjtTypeIndex = ref(-1)
|
|
|
- const needInputDeptInfo = ref(false)
|
|
|
- // 级联选择器相关数据
|
|
|
- const cascadeData = ref({
|
|
|
- level1: <any[]>[],
|
|
|
- level2: <any[]>[],
|
|
|
- level3: <any[]>[],
|
|
|
- })
|
|
|
- const selectedLevel1 = ref<any>(null)
|
|
|
- const selectedLevel2 = ref<any>(null)
|
|
|
- const selectedLevel3 = ref<any>(null)
|
|
|
-
|
|
|
- const userTypeList = ref(<RowDicDataType[]>[])
|
|
|
- const userSexList = ref(<RowDicDataType[]>[])
|
|
|
- const userCertList = ref(<RowDicDataType[]>[])
|
|
|
- const deptData = ref(<any[]>[])
|
|
|
- const pjtList = ref(<any[]>[])
|
|
|
- const pjtTypeList = ref(<any[]>[])
|
|
|
- const state = reactive({
|
|
|
- active: 0,
|
|
|
- loading: {
|
|
|
- signIn: false,
|
|
|
- },
|
|
|
- form: {
|
|
|
- id: 0,
|
|
|
- userName: '', // 账户名称
|
|
|
- nickName: '', // 用户姓名
|
|
|
- userType: '10', // 关联角色
|
|
|
- deptId: null,
|
|
|
- deptName: '', // 单位名称
|
|
|
- phone: '', // 手机号
|
|
|
- email: '', // 邮箱
|
|
|
- sex: '30', // 性别
|
|
|
- password: '', // 账户密码
|
|
|
- confirmPassword: '',
|
|
|
- status: '10', // 用户状态
|
|
|
- describe: '', // 用户描述
|
|
|
- avatar: '',
|
|
|
- idType: '', //证件类型
|
|
|
- idCode: '', // 证件号
|
|
|
- personnelType: '', // 人员类型
|
|
|
- projectId: null,
|
|
|
+import { onMounted, reactive, ref, watch } from 'vue'
|
|
|
+import to from 'await-to-js'
|
|
|
+import { useLoginApi } from '/@/api/login/index'
|
|
|
+import crypto from 'sm-crypto'
|
|
|
+import { useDictApi } from '/@/api/system/dict'
|
|
|
+import { useProApi } from '/@/api/project'
|
|
|
+import { useDeptApi } from '/@/api/system/dept'
|
|
|
+import { useRouter, useRoute } from 'vue-router'
|
|
|
+import { showNotify } from 'vant'
|
|
|
+
|
|
|
+import { UserTypeTooltip } from '/@/constants/pageConstants'
|
|
|
+import { isPasswordValid } from '/@/utils/stringUtils'
|
|
|
+
|
|
|
+const sm3 = crypto.sm3
|
|
|
+const loginApi = useLoginApi()
|
|
|
+const router = useRouter()
|
|
|
+const dictApi = useDictApi()
|
|
|
+const proApi = useProApi()
|
|
|
+const deptApi = useDeptApi()
|
|
|
+const loginInfoRef = ref()
|
|
|
+const personInfoRef = ref()
|
|
|
+const projectInfoRef = ref()
|
|
|
+const showDeptPicker = ref(false)
|
|
|
+const showPjtPicker = ref(false)
|
|
|
+const showPjtDatePicker = ref(false)
|
|
|
+const showPjtTypePicker = ref(false)
|
|
|
+const show = ref(false)
|
|
|
+const pjtTypeIndex = ref(-1)
|
|
|
+const needInputDeptInfo = ref(false)
|
|
|
+// 级联选择器相关数据
|
|
|
+const cascadeData = ref({
|
|
|
+ level1: <any[]>[],
|
|
|
+ level2: <any[]>[],
|
|
|
+ level3: <any[]>[],
|
|
|
+})
|
|
|
+const selectedLevel1 = ref<any>(null)
|
|
|
+const selectedLevel2 = ref<any>(null)
|
|
|
+const selectedLevel3 = ref<any>(null)
|
|
|
+
|
|
|
+const userTypeList = ref(<RowDicDataType[]>[])
|
|
|
+const userSexList = ref(<RowDicDataType[]>[])
|
|
|
+const userCertList = ref(<RowDicDataType[]>[])
|
|
|
+const deptData = ref(<any[]>[])
|
|
|
+const pjtList = ref(<any[]>[])
|
|
|
+const pjtTypeList = ref(<any[]>[])
|
|
|
+const state = reactive({
|
|
|
+ active: 0,
|
|
|
+ loading: {
|
|
|
+ signIn: false,
|
|
|
+ },
|
|
|
+ form: {
|
|
|
+ id: 0,
|
|
|
+ userName: '', // 账户名称
|
|
|
+ nickName: '', // 用户姓名
|
|
|
+ userType: '10', // 关联角色
|
|
|
+ deptId: null,
|
|
|
+ deptName: '', // 单位名称
|
|
|
+ phone: '', // 手机号
|
|
|
+ email: '', // 邮箱
|
|
|
+ sex: '30', // 性别
|
|
|
+ password: '', // 账户密码
|
|
|
+ confirmPassword: '',
|
|
|
+ status: '10', // 用户状态
|
|
|
+ describe: '', // 用户描述
|
|
|
+ avatar: '',
|
|
|
+ idType: '', //证件类型
|
|
|
+ idCode: '', // 证件号
|
|
|
+ personnelType: '', // 人员类型
|
|
|
+ projectId: null,
|
|
|
+ projectName: '',
|
|
|
+ projectDate: '',
|
|
|
+ startDate: [],
|
|
|
+ endDate: [],
|
|
|
+ registerType: '10',
|
|
|
+ applyPg: {},
|
|
|
+ projectGroupName: '',
|
|
|
+ projectGroupId: null,
|
|
|
+ projectList: <any[]>[{
|
|
|
projectName: '',
|
|
|
- projectDate: '',
|
|
|
- startDate: [],
|
|
|
- endDate: [],
|
|
|
- registerType: '10',
|
|
|
- applyPg: {},
|
|
|
- projectGroupName: '',
|
|
|
- projectGroupId: null,
|
|
|
- projectList: <any[]>[],
|
|
|
- unitName: '',
|
|
|
- deptDescribe: '',
|
|
|
- },
|
|
|
+ projectType: '',
|
|
|
+ projectTypeName: '',
|
|
|
+ projectSource: '',
|
|
|
+ }],
|
|
|
+ unitName: '',
|
|
|
+ deptDescribe: '',
|
|
|
+ },
|
|
|
+})
|
|
|
+const deptDataBackup = ref(<any[]>[])
|
|
|
+
|
|
|
+const getDicts = () => {
|
|
|
+ Promise.all([
|
|
|
+ dictApi.getDictDataByType('sys_user_type'),
|
|
|
+ dictApi.getDictDataByType('sys_com_sex'),
|
|
|
+ dictApi.getDictDataByType('sys_user_certificate'),
|
|
|
+ deptApi.getDeptTree(),
|
|
|
+ proApi.getProjectGroupListForApp({ noPage: true }),
|
|
|
+ dictApi.getDictDataByType('sci_pjt_level'),
|
|
|
+ ]).then(([type, sex, cert, dept, pjt, pjtType]) => {
|
|
|
+ userTypeList.value = type.data.values || []
|
|
|
+ userSexList.value = sex.data.values || []
|
|
|
+ userCertList.value = cert.data.values || []
|
|
|
+ deptDataBackup.value = dept.data || []
|
|
|
+ deptData.value = dept.data || []
|
|
|
+ pjtList.value = pjt.data.list || []
|
|
|
+ pjtTypeList.value = pjtType.data.values || []
|
|
|
+
|
|
|
+ // 初始化级联数据
|
|
|
+ initCascadeData()
|
|
|
})
|
|
|
- const deptDataBackup = ref(<any[]>[])
|
|
|
-
|
|
|
- const getDicts = () => {
|
|
|
- Promise.all([
|
|
|
- dictApi.getDictDataByType('sys_user_type'),
|
|
|
- dictApi.getDictDataByType('sys_com_sex'),
|
|
|
- dictApi.getDictDataByType('sys_user_certificate'),
|
|
|
- deptApi.getDeptTree(),
|
|
|
- proApi.getProjectGroupListForApp({ noPage: true }),
|
|
|
- dictApi.getDictDataByType('sci_pjt_level'),
|
|
|
- ]).then(([type, sex, cert, dept, pjt, pjtType]) => {
|
|
|
- userTypeList.value = type.data.values || []
|
|
|
- userSexList.value = sex.data.values || []
|
|
|
- userCertList.value = cert.data.values || []
|
|
|
- deptDataBackup.value = dept.data || []
|
|
|
- deptData.value = dept.data || []
|
|
|
- pjtList.value = pjt.data.list || []
|
|
|
- pjtTypeList.value = pjtType.data.values || []
|
|
|
-
|
|
|
- // 初始化级联数据
|
|
|
- initCascadeData()
|
|
|
- })
|
|
|
- }
|
|
|
+}
|
|
|
|
|
|
- const checkUserNamePhoneExists = async (type: 'userName' | 'phone') => {
|
|
|
- let resquest = loginApi.checkUserNamePhoneExists({ userName: state.form.userName, phone: '' })
|
|
|
+const checkUserNamePhoneExists = async (type: 'userName' | 'phone') => {
|
|
|
+ let resquest = loginApi.checkUserNamePhoneExists({ userName: state.form.userName, phone: '' })
|
|
|
|
|
|
- if (type === 'phone') {
|
|
|
- resquest = loginApi.checkUserNamePhoneExists({ userName: '', phone: state.form.phone })
|
|
|
- }
|
|
|
-
|
|
|
- await to(resquest)
|
|
|
+ if (type === 'phone') {
|
|
|
+ resquest = loginApi.checkUserNamePhoneExists({ userName: '', phone: state.form.phone })
|
|
|
}
|
|
|
|
|
|
- const renderDeptData = () => {
|
|
|
- let daptTree = deptDataBackup.value
|
|
|
+ await to(resquest)
|
|
|
+}
|
|
|
|
|
|
- if (state.form.userType === '10') {
|
|
|
- daptTree = daptTree.filter((item) => item.id === 100001)
|
|
|
- }
|
|
|
+const renderDeptData = () => {
|
|
|
+ let daptTree = deptDataBackup.value
|
|
|
|
|
|
- if (state.form.userType === '15') {
|
|
|
- daptTree = daptTree.filter((item) => item.id !== 1000220)
|
|
|
- }
|
|
|
+ if (state.form.userType === '10') {
|
|
|
+ daptTree = daptTree.filter((item) => item.id === 100001)
|
|
|
+ }
|
|
|
|
|
|
- if (state.form.userType === '20') {
|
|
|
- daptTree = daptTree.filter((item) => item.id === 1000220)
|
|
|
- }
|
|
|
+ if (state.form.userType === '15') {
|
|
|
+ daptTree = daptTree.filter((item) => item.id !== 1000220)
|
|
|
+ }
|
|
|
|
|
|
- return daptTree
|
|
|
+ if (state.form.userType === '20') {
|
|
|
+ daptTree = daptTree.filter((item) => item.id === 1000220)
|
|
|
}
|
|
|
|
|
|
- const deptIncludesProjectGroup = async (deptId: number) => {
|
|
|
- const [err, res]: ToResponse = await to(
|
|
|
- proApi.getProjectGroupList({
|
|
|
- pgOrg: deptId,
|
|
|
- pgName: '',
|
|
|
- pageNum: 1,
|
|
|
- pageSize: 1000,
|
|
|
- }),
|
|
|
- )
|
|
|
- if (err) return
|
|
|
+ return daptTree
|
|
|
+}
|
|
|
+
|
|
|
+const deptIncludesProjectGroup = async (deptId: number) => {
|
|
|
+ const [err, res]: ToResponse = await to(
|
|
|
+ proApi.getProjectGroupList({
|
|
|
+ pgOrg: deptId,
|
|
|
+ pgName: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000,
|
|
|
+ }),
|
|
|
+ )
|
|
|
+ if (err) return
|
|
|
|
|
|
- pjtList.value = res?.data.list || []
|
|
|
- }
|
|
|
+ pjtList.value = res?.data.list || []
|
|
|
+}
|
|
|
|
|
|
- const preStep = () => {
|
|
|
- state.active--
|
|
|
- }
|
|
|
- const nextStep = async () => {
|
|
|
- if (state.active < 3) {
|
|
|
- let form = loginInfoRef.value
|
|
|
- if (state.active == 1) {
|
|
|
- form = personInfoRef.value
|
|
|
- } else if (state.active == 2) {
|
|
|
- form = projectInfoRef.value
|
|
|
- }
|
|
|
- const [err, res] = await to(form.validate())
|
|
|
- if (err) return
|
|
|
- state.active++
|
|
|
- }
|
|
|
+const preStep = () => {
|
|
|
+ state.active--
|
|
|
+}
|
|
|
+const validateProjectList = () => {
|
|
|
+ // 校验至少有一个项目
|
|
|
+ if (!state.form.projectList || state.form.projectList.length === 0) {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: '请至少添加一个项目',
|
|
|
+ })
|
|
|
+ return false
|
|
|
}
|
|
|
|
|
|
- const checkPassword = (value: any) => {
|
|
|
- let checkResult = isPasswordValid(value)
|
|
|
- if(!checkResult.isPassed){
|
|
|
- return checkResult.errorMsg
|
|
|
+ // 校验每个项目的必填字段
|
|
|
+ for (let i = 0; i < state.form.projectList.length; i++) {
|
|
|
+ const item = state.form.projectList[i]
|
|
|
+ if (!item.projectName || !item.projectName.trim()) {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: `项目 ${i + 1} 的项目名称不能为空`,
|
|
|
+ })
|
|
|
+ return false
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- const confirmPasswordSame = (value: any) => {
|
|
|
- if (!value) {
|
|
|
+ if (!item.projectType || !item.projectTypeName) {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: `项目 ${i + 1} 的项目类型不能为空`,
|
|
|
+ })
|
|
|
return false
|
|
|
- } else if (value !== state.form.password) {
|
|
|
+ }
|
|
|
+ if (!item.projectSource || !item.projectSource.trim()) {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: `项目 ${i + 1} 的项目来源不能为空`,
|
|
|
+ })
|
|
|
return false
|
|
|
- } else {
|
|
|
- return true
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- watch(
|
|
|
- () => state.form.userType,
|
|
|
- (newVal) => {
|
|
|
- if (newVal === '20') {
|
|
|
- state.form.idType = '30'
|
|
|
- needInputDeptInfo.value = true
|
|
|
- } else {
|
|
|
- state.form.idType = '20'
|
|
|
- state.form.deptId = null
|
|
|
- state.form.deptName = ''
|
|
|
- needInputDeptInfo.value = false
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+const nextStep = async () => {
|
|
|
+ if (state.active < 3) {
|
|
|
+ let form = loginInfoRef.value
|
|
|
+ if (state.active == 1) {
|
|
|
+ form = personInfoRef.value
|
|
|
+ } else if (state.active == 2) {
|
|
|
+ form = projectInfoRef.value
|
|
|
+ // 校验项目列表
|
|
|
+ if (!validateProjectList()) {
|
|
|
+ return
|
|
|
}
|
|
|
- },
|
|
|
- { immediate: true },
|
|
|
- )
|
|
|
-
|
|
|
- const changeType = (val: string) => {
|
|
|
- state.form.registerType = val
|
|
|
- if (val === '10' && state.active == 2) {
|
|
|
- state.active = 1
|
|
|
+ // 校验表单字段
|
|
|
+ const [err] = await to(form.validate())
|
|
|
+ if (err) return
|
|
|
+ state.active++
|
|
|
+ return
|
|
|
}
|
|
|
+ const [err, res] = await to(form.validate())
|
|
|
+ if (err) return
|
|
|
+ state.active++
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- const showDeptPickerHandler = () => {
|
|
|
- initCascadeData()
|
|
|
- showDeptPicker.value = true
|
|
|
- }
|
|
|
- const onPjtPicker = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
- showPjtPicker.value = false
|
|
|
- state.form.projectGroupName = selectedOptions[0].pgName
|
|
|
- state.form.projectGroupId = selectedOptions[0].id
|
|
|
+const checkPassword = (value: any) => {
|
|
|
+ let checkResult = isPasswordValid(value)
|
|
|
+ if (!checkResult.isPassed) {
|
|
|
+ return checkResult.errorMsg
|
|
|
}
|
|
|
- const onPjtDatePicker = () => {
|
|
|
- showPjtDatePicker.value = false
|
|
|
- state.form.projectDate = `${state.form.startDate.join('-')}至${state.form.endDate.join('-')}`
|
|
|
+}
|
|
|
+
|
|
|
+const confirmPasswordSame = (value: any) => {
|
|
|
+ if (!value) {
|
|
|
+ return false
|
|
|
+ } else if (value !== state.form.password) {
|
|
|
+ return false
|
|
|
+ } else {
|
|
|
+ return true
|
|
|
}
|
|
|
- const addProject = () => {
|
|
|
- state.form.projectList.push({
|
|
|
- projectName: '',
|
|
|
- projectType: '',
|
|
|
- projectTypeName: '',
|
|
|
- projectSource: '',
|
|
|
- })
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => state.form.userType,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal === '20') {
|
|
|
+ state.form.idType = '30'
|
|
|
+ needInputDeptInfo.value = true
|
|
|
+ } else {
|
|
|
+ state.form.idType = '20'
|
|
|
+ state.form.deptId = null
|
|
|
+ state.form.deptName = ''
|
|
|
+ needInputDeptInfo.value = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true },
|
|
|
+)
|
|
|
+
|
|
|
+const changeType = (val: string) => {
|
|
|
+ state.form.registerType = val
|
|
|
+ if (val === '10' && state.active == 2) {
|
|
|
+ state.active = 1
|
|
|
}
|
|
|
- const delProjectItem = (idx: number) => {
|
|
|
+}
|
|
|
+
|
|
|
+const showDeptPickerHandler = () => {
|
|
|
+ initCascadeData()
|
|
|
+ showDeptPicker.value = true
|
|
|
+}
|
|
|
+const onPjtPicker = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
+ showPjtPicker.value = false
|
|
|
+ state.form.projectGroupName = selectedOptions[0].pgName
|
|
|
+ state.form.projectGroupId = selectedOptions[0].id
|
|
|
+}
|
|
|
+const onPjtDatePicker = () => {
|
|
|
+ showPjtDatePicker.value = false
|
|
|
+ state.form.projectDate = `${state.form.startDate.join('-')}至${state.form.endDate.join('-')}`
|
|
|
+}
|
|
|
+const addProject = () => {
|
|
|
+ state.form.projectList.push({
|
|
|
+ projectName: '',
|
|
|
+ projectType: '',
|
|
|
+ projectTypeName: '',
|
|
|
+ projectSource: '',
|
|
|
+ })
|
|
|
+}
|
|
|
+const delProjectItem = (idx: number) => {
|
|
|
+ if (state.form.projectList.length > 1) {
|
|
|
state.form.projectList.splice(idx, 1)
|
|
|
+ } else {
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: '至少需要保留一个项目',
|
|
|
+ })
|
|
|
}
|
|
|
- const openPjtType = (row: any, idx: number) => {
|
|
|
- pjtTypeIndex.value = idx
|
|
|
- showPjtTypePicker.value = true
|
|
|
- }
|
|
|
- const onPjtTypePicker = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
- showPjtTypePicker.value = false
|
|
|
- state.form.projectList[pjtTypeIndex.value].projectType = selectedOptions[0].dictValue
|
|
|
- state.form.projectList[pjtTypeIndex.value].projectTypeName = selectedOptions[0].dictLabel
|
|
|
- }
|
|
|
-
|
|
|
- watch(
|
|
|
- () => state.form.deptId,
|
|
|
- (newVal) => {
|
|
|
- if (newVal) {
|
|
|
- deptIncludesProjectGroup(newVal)
|
|
|
- }
|
|
|
- },
|
|
|
- )
|
|
|
-
|
|
|
- // 级联选择器方法
|
|
|
- const initCascadeData = () => {
|
|
|
- cascadeData.value.level1 = renderDeptData()
|
|
|
+}
|
|
|
+const openPjtType = (row: any, idx: number) => {
|
|
|
+ pjtTypeIndex.value = idx
|
|
|
+ showPjtTypePicker.value = true
|
|
|
+}
|
|
|
+const onPjtTypePicker = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
+ showPjtTypePicker.value = false
|
|
|
+ state.form.projectList[pjtTypeIndex.value].projectType = selectedOptions[0].dictValue
|
|
|
+ state.form.projectList[pjtTypeIndex.value].projectTypeName = selectedOptions[0].dictLabel
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => state.form.deptId,
|
|
|
+ (newVal) => {
|
|
|
+ if (newVal) {
|
|
|
+ deptIncludesProjectGroup(newVal)
|
|
|
+ }
|
|
|
+ },
|
|
|
+)
|
|
|
+
|
|
|
+// 级联选择器方法
|
|
|
+const initCascadeData = () => {
|
|
|
+ cascadeData.value.level1 = renderDeptData()
|
|
|
+ cascadeData.value.level2 = []
|
|
|
+ cascadeData.value.level3 = []
|
|
|
+ selectedLevel1.value = null
|
|
|
+ selectedLevel2.value = null
|
|
|
+ selectedLevel3.value = null
|
|
|
+}
|
|
|
+
|
|
|
+const selectLevel1 = (item: any) => {
|
|
|
+ selectedLevel1.value = item
|
|
|
+ selectedLevel2.value = null
|
|
|
+ selectedLevel3.value = null
|
|
|
+
|
|
|
+ if (item.children && item.children.length > 0) {
|
|
|
+ cascadeData.value.level2 = item.children
|
|
|
+ cascadeData.value.level3 = []
|
|
|
+ } else {
|
|
|
cascadeData.value.level2 = []
|
|
|
cascadeData.value.level3 = []
|
|
|
- selectedLevel1.value = null
|
|
|
- selectedLevel2.value = null
|
|
|
- selectedLevel3.value = null
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- const selectLevel1 = (item: any) => {
|
|
|
- selectedLevel1.value = item
|
|
|
- selectedLevel2.value = null
|
|
|
- selectedLevel3.value = null
|
|
|
+const selectLevel2 = (item: any) => {
|
|
|
+ selectedLevel2.value = item
|
|
|
+ selectedLevel3.value = null
|
|
|
|
|
|
- if (item.children && item.children.length > 0) {
|
|
|
- cascadeData.value.level2 = item.children
|
|
|
- cascadeData.value.level3 = []
|
|
|
- } else {
|
|
|
- cascadeData.value.level2 = []
|
|
|
- cascadeData.value.level3 = []
|
|
|
+ if (item.children && item.children.length > 0) {
|
|
|
+ cascadeData.value.level3 = item.children
|
|
|
+ } else {
|
|
|
+ cascadeData.value.level3 = []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const selectLevel3 = (item: any) => {
|
|
|
+ selectedLevel3.value = item
|
|
|
+}
|
|
|
+
|
|
|
+const confirmCascadeSelection = () => {
|
|
|
+ const selectedItem = selectedLevel3.value || selectedLevel2.value || selectedLevel1.value
|
|
|
+ if (selectedItem) {
|
|
|
+ state.form.deptName = selectedItem.deptName
|
|
|
+ state.form.deptId = selectedItem.id
|
|
|
+ showDeptPicker.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const onRegister = async () => {
|
|
|
+ const form = state.form.registerType == '10' ? personInfoRef.value : personInfoRef.value
|
|
|
+ const [error] = await to(form.validate())
|
|
|
+ if (error) return
|
|
|
+
|
|
|
+ // 如果是课题组负责人,需要校验项目信息
|
|
|
+ if (state.form.registerType === '20') {
|
|
|
+ if (!validateProjectList()) {
|
|
|
+ return
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ const params = JSON.parse(JSON.stringify(state.form))
|
|
|
+ params.password = sm3(params.password)
|
|
|
+ delete params.confirmPassword
|
|
|
+ params.startDate = params.startDate.join('-')
|
|
|
+ params.endDate = params.endDate.join('-')
|
|
|
+ delete params.projectDate
|
|
|
+ const [err] = await to(loginApi.register(params))
|
|
|
+ if (err) {
|
|
|
+ // show.value = true
|
|
|
+ // setTimeout(() => {
|
|
|
+ // show.value = false
|
|
|
+ // }, 2000)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ showNotify({
|
|
|
+ type: 'success',
|
|
|
+ message:
|
|
|
+ state.form.registerType === '20'
|
|
|
+ ? '你已经注册为课题组负责人,等待系统管理员审核通过'
|
|
|
+ : '你已经注册为课题组成员,等待课题组负责人审核通过',
|
|
|
+ })
|
|
|
+ router.push('/login')
|
|
|
+}
|
|
|
+onMounted(async () => {
|
|
|
+ getDicts()
|
|
|
+})
|
|
|
+</script>
|
|
|
|
|
|
- const selectLevel2 = (item: any) => {
|
|
|
- selectedLevel2.value = item
|
|
|
- selectedLevel3.value = null
|
|
|
+<style lang="scss" scoped>
|
|
|
+.register {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: calc(100% - 20px);
|
|
|
|
|
|
- if (item.children && item.children.length > 0) {
|
|
|
- cascadeData.value.level3 = item.children
|
|
|
- } else {
|
|
|
- cascadeData.value.level3 = []
|
|
|
+ .van-row .van-button {
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ &+.van-button {
|
|
|
+ margin-left: 10px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const selectLevel3 = (item: any) => {
|
|
|
- selectedLevel3.value = item
|
|
|
+ .form {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
- const confirmCascadeSelection = () => {
|
|
|
- const selectedItem = selectedLevel3.value || selectedLevel2.value || selectedLevel1.value
|
|
|
- if (selectedItem) {
|
|
|
- state.form.deptName = selectedItem.deptName
|
|
|
- state.form.deptId = selectedItem.id
|
|
|
- showDeptPicker.value = false
|
|
|
- }
|
|
|
+ footer {
|
|
|
+ padding: 0 10px 10px;
|
|
|
+ flex: 0 0 40px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- const onRegister = async () => {
|
|
|
- const form = state.form.registerType == '10' ? personInfoRef.value : personInfoRef.value
|
|
|
- const [error] = await to(form.validate())
|
|
|
- if (error) return
|
|
|
- const params = JSON.parse(JSON.stringify(state.form))
|
|
|
- params.password = sm3(params.password)
|
|
|
- delete params.confirmPassword
|
|
|
- params.startDate = params.startDate.join('-')
|
|
|
- params.endDate = params.endDate.join('-')
|
|
|
- delete params.projectDate
|
|
|
- const [err] = await to(loginApi.register(params))
|
|
|
- if (err) {
|
|
|
- show.value = true
|
|
|
- setTimeout(() => {
|
|
|
- show.value = false
|
|
|
- }, 2000)
|
|
|
- return
|
|
|
+.cascade-picker {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px 8px 0 0;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .cascade-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 16px;
|
|
|
+ border-bottom: 1px solid #f5f5f5;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+
|
|
|
+ .van-icon {
|
|
|
+ font-size: 18px;
|
|
|
+ color: #969799;
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
- showNotify({
|
|
|
- type: 'success',
|
|
|
- message:
|
|
|
- state.form.registerType === '20'
|
|
|
- ? '你已经注册为课题组负责人,等待系统管理员审核通过'
|
|
|
- : '你已经注册为课题组成员,等待课题组负责人审核通过',
|
|
|
- })
|
|
|
- router.push('/login')
|
|
|
}
|
|
|
- onMounted(async () => {
|
|
|
- getDicts()
|
|
|
- })
|
|
|
-</script>
|
|
|
|
|
|
-<style lang="scss" scoped>
|
|
|
- .register {
|
|
|
+ .cascade-content {
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
- height: calc(100% - 20px);
|
|
|
- .van-row .van-button {
|
|
|
+ height: 300px;
|
|
|
+
|
|
|
+ .cascade-column {
|
|
|
flex: 1;
|
|
|
- & + .van-button {
|
|
|
- margin-left: 10px;
|
|
|
+ border-right: 1px solid #f5f5f5;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ border-right: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .cascade-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 12px 16px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: #f7f8fa;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background-color: #e8f3ff;
|
|
|
+ color: #1989fa;
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .van-icon {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #c8c9cc;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- .form {
|
|
|
+ }
|
|
|
+
|
|
|
+ .cascade-footer {
|
|
|
+ display: flex;
|
|
|
+ padding: 12px 16px;
|
|
|
+ border-top: 1px solid #f5f5f5;
|
|
|
+ gap: 12px;
|
|
|
+
|
|
|
+ .van-button {
|
|
|
flex: 1;
|
|
|
- overflow-y: auto;
|
|
|
- }
|
|
|
- footer {
|
|
|
- padding: 0 10px 10px;
|
|
|
- flex: 0 0 40px;
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+.project-list-container {
|
|
|
+ padding: 12px;
|
|
|
+
|
|
|
+ .add-project-btn {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .empty-project-tip {
|
|
|
+ padding: 20px;
|
|
|
+ text-align: center;
|
|
|
+ color: #969799;
|
|
|
+ font-size: 14px;
|
|
|
+ background-color: #f7f8fa;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ }
|
|
|
|
|
|
- .cascade-picker {
|
|
|
+ .project-card {
|
|
|
background: #fff;
|
|
|
- border-radius: 8px 8px 0 0;
|
|
|
+ border: 1px solid #ebedf0;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
overflow: hidden;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
+ transition: box-shadow 0.3s;
|
|
|
|
|
|
- .cascade-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: 16px;
|
|
|
- border-bottom: 1px solid #f5f5f5;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 500;
|
|
|
-
|
|
|
- .van-icon {
|
|
|
- font-size: 18px;
|
|
|
- color: #969799;
|
|
|
- cursor: pointer;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
|
}
|
|
|
|
|
|
- .cascade-content {
|
|
|
+ .project-card-header {
|
|
|
display: flex;
|
|
|
- height: 300px;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 12px 16px;
|
|
|
+ background: linear-gradient(135deg, #1989fa 0%, #0050b3 100%);
|
|
|
+ color: #fff;
|
|
|
|
|
|
- .cascade-column {
|
|
|
- flex: 1;
|
|
|
- border-right: 1px solid #f5f5f5;
|
|
|
- overflow-y: auto;
|
|
|
+ .project-card-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ }
|
|
|
|
|
|
- &:last-child {
|
|
|
- border-right: none;
|
|
|
- }
|
|
|
+ .delete-btn {
|
|
|
+ background: rgba(255, 255, 255, 0.2);
|
|
|
+ border-color: rgba(255, 255, 255, 0.3);
|
|
|
+ color: #fff;
|
|
|
|
|
|
- .cascade-item {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: 12px 16px;
|
|
|
- cursor: pointer;
|
|
|
- transition: background-color 0.2s;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- background-color: #f7f8fa;
|
|
|
- }
|
|
|
-
|
|
|
- &.active {
|
|
|
- background-color: #e8f3ff;
|
|
|
- color: #1989fa;
|
|
|
- }
|
|
|
-
|
|
|
- span {
|
|
|
- flex: 1;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
-
|
|
|
- .van-icon {
|
|
|
- font-size: 12px;
|
|
|
- color: #c8c9cc;
|
|
|
- }
|
|
|
+ &:hover {
|
|
|
+ background: rgba(255, 255, 255, 0.3);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- .cascade-footer {
|
|
|
- display: flex;
|
|
|
- padding: 12px 16px;
|
|
|
- border-top: 1px solid #f5f5f5;
|
|
|
- gap: 12px;
|
|
|
+ .project-card-body {
|
|
|
+ padding: 12px 0;
|
|
|
|
|
|
- .van-button {
|
|
|
- flex: 1;
|
|
|
+ .project-field {
|
|
|
+ margin-bottom: 8px;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+}
|
|
|
</style>
|