agreementAdd.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <template>
  2. <div>
  3. <PageMain style="padding: 20px;margin-bottom: 100px;">
  4. <ElRow :gutter="60">
  5. <ElCol :md="24" :lg="24" style="padding-bottom: 10px;font-size: 14px;">
  6. <span class="strong">协议信息</span>
  7. </ElCol>
  8. <el-form :model="agreementFrom" label-width="120px" :rules="agreementFromRules" label-position="top"
  9. ref="agreementFromRef" style="max-width: 100%;" class="flex a-c f-wrap" :size="fromSize">
  10. <ElCol :md="24" :lg="6">
  11. <el-form-item label="协议名称" prop="agreementTitle">
  12. <el-input v-model="agreementFrom.agreementTitle" placeholder="输入协议名称" maxlength="50"
  13. show-word-limit></el-input>
  14. </el-form-item>
  15. </ElCol>
  16. <ElCol :md="24" :lg="6">
  17. <el-form-item label="协议简称" prop="agreementAbbreviation">
  18. <el-input v-model="agreementFrom.agreementAbbreviation" placeholder="输入简称" maxlength="50"
  19. show-word-limit />
  20. </el-form-item>
  21. </ElCol>
  22. <ElCol :md="24" :lg="6">
  23. <el-form-item label="协议生效时间" prop="startDate">
  24. <el-date-picker v-model="agreementFrom.startDate" style="width: 100%;" type="datetime"
  25. placeholder="选择生效时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
  26. time-format="HH:mm:ss" @change="handleStartDateChange" />
  27. </el-form-item>
  28. </ElCol>
  29. <ElCol :md="24" :lg="6">
  30. <el-form-item label="协议失效时间" prop="endDate">
  31. <el-date-picker v-model="agreementFrom.endDate" style="width: 100%;" type="datetime" placeholder="选择失效时间"
  32. format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss"
  33. :disabled-date="disabledEndDate" />
  34. </el-form-item>
  35. </ElCol>
  36. <ElCol :md="24" :lg="6">
  37. <el-form-item label="是否含增值税结算" prop="withTax">
  38. <el-radio-group v-model="agreementFrom.withTax">
  39. <el-radio-button :label="item.label" :value="item.value" v-for="(item, index) in getDict('with_tax')"
  40. :key="index" />
  41. </el-radio-group>
  42. </el-form-item>
  43. </ElCol>
  44. <ElCol :md="24" :lg="6">
  45. <el-form-item label="结算周期" prop="moneyTime">
  46. <span style="margin: 0 20px;font-size: 18px;">T</span>
  47. <el-input-number v-model="agreementFrom.moneyTime" :min="1" :max="999" />
  48. </el-form-item>
  49. </ElCol>
  50. <ElCol :md="24" :lg="12"></ElCol>
  51. <ElCol :md="24" :lg="12">
  52. <el-form-item label="协议描述" prop="agreementName">
  53. <el-input v-model="agreementFrom.agreementName" placeholder="请输入" type="textarea" maxlength="500"
  54. show-word-limit />
  55. </el-form-item>
  56. </ElCol>
  57. <ElCol :md="24" :lg="24" style="padding-bottom: 10px;font-size: 14px;">
  58. <ElDivider></ElDivider>
  59. <span class="strong">其他信息</span>
  60. </ElCol>
  61. <ElCol :md="24" :lg="6">
  62. <el-form-item label="协议归属" prop="deptId">
  63. <el-cascader v-model="agreementFrom.deptId" style="width: 100%;" filterable clearable
  64. :options="deptOptions" :props="parentIdprops" :show-all-levels="false" @change="deptIdChange" />
  65. </el-form-item>
  66. </ElCol>
  67. <ElCol :md="24" :lg="6">
  68. <el-form-item label="保险公司" prop="companyId">
  69. <el-cascader v-model="agreementFrom.companyId" style="width: 100%;" filterable clearable
  70. :options="companyOptions" :props="companyIdprops" :show-all-levels="false" @change="companyIdChange" />
  71. </el-form-item>
  72. </ElCol>
  73. <ElCol :md="24" :lg="6">
  74. <el-form-item label="协议类型" prop="agreementType">
  75. <el-select v-model="agreementFrom.agreementType" placeholder="选择协议类型">
  76. <el-option :label="item.label" :value="item.value" v-for="(item, index) in getDict('agreement_type')"
  77. :key="index" />
  78. </el-select>
  79. </el-form-item>
  80. </ElCol>
  81. <ElCol :md="24" :lg="6">
  82. <el-form-item label="管理人" prop="custodianId">
  83. <el-input v-model="managerName" @click="managerModalVisible = true">{{ agreementFrom.custodianId
  84. }}</el-input>
  85. </el-form-item>
  86. </ElCol>
  87. </el-form>
  88. </ElRow>
  89. </PageMain>
  90. <FixedActionBar>
  91. <ElButton type="primary" @click="submitForm(agreementFromRef)">
  92. 保存
  93. </ElButton>
  94. <ElButton @click="router.back()">
  95. 取消
  96. </ElButton>
  97. </FixedActionBar>
  98. <!-- 选择管理人 -->
  99. <managerModal :managerModal="managerModalVisible" :deptOptions="deptOptions" :managerlist="managerlist"
  100. @save="managerModalsave" @NodeClick="managerModalNodeClick" @query="managerModalQuery" @cancel="managerModalVisible = false" />
  101. </div>
  102. </template>
  103. <script lang="ts" setup>
  104. import { ref, reactive } from 'vue'
  105. import { FormRules, FormInstance, ComponentSize, ElMessage } from 'element-plus';
  106. import { loadDicts, getDict } from '@/utils/composables/dictService';//字典组件
  107. import { useRoute, useRouter } from 'vue-router';
  108. import managerModal from "./components/managerModal.vue";
  109. import api from '@/api';
  110. const parentIdprops = {
  111. expandTrigger: 'hover' as const,
  112. value: 'id',
  113. label: 'name',
  114. checkStrictly: true,
  115. }
  116. const companyIdprops = {
  117. expandTrigger: 'hover' as const,
  118. value: 'id',
  119. label: 'nameSimple',
  120. checkStrictly: true,
  121. }
  122. interface AgreementForm {
  123. id?: string; // 协议 ID
  124. agreementTitle: string; // 协议名称
  125. agreementAbbreviation: string; // 协议简称
  126. startDate: string; // 生效时间,通常为 ISO 格式的日期字符串
  127. endDate: string; // 失效时间,通常为 ISO 格式的日期字符串
  128. withTax: string; // 是否含增值税结算
  129. moneyTime: any; // 结算周期
  130. agreementName: string; // 协议描述
  131. deptId: string; // 协议归属
  132. companyId: string; // 保险公司 ID
  133. agreementType: string; // 协议类型
  134. custodianId: string; // 管理人 ID
  135. }
  136. const route = useRoute();
  137. const router = useRouter();
  138. const id = ref(route.query.id as string);//id参数
  139. const deptOptions = ref([])//机构数据
  140. const companyOptions = ref()//保险公司数据
  141. const agreementFromRef = ref<FormInstance>()
  142. const fromSize = ref<ComponentSize>('large')
  143. const agreementFrom: AgreementForm = reactive({
  144. id: "",
  145. agreementTitle: "",//协议名称
  146. agreementAbbreviation: "",//协议简称
  147. startDate: "",//生效时间
  148. endDate: "",//失效时间
  149. withTax: "",//是否含增值税结算
  150. moneyTime: 0,//结算周期
  151. agreementName: "",//协议描述
  152. deptId: "",//协议归属
  153. companyId: "",//保险公司id
  154. agreementType: "",//协议类型
  155. custodianId: "",//管理人id
  156. })
  157. const validatepassword = (_rule: any, value: any, callback: any) => {
  158. // 定义正则表达式,例如:只允许字母、数字,长度在4到10个字符之间
  159. const codeRegex = /^(?:(?:\+|00)86)?1\d{10}$/;
  160. // 判断是否为空
  161. if (!value) {
  162. return callback(new Error('请输入手机号'));
  163. }
  164. // 验证是否符合正则表达式
  165. if (!codeRegex.test(value)) {
  166. return callback(new Error('请输入正确的手机号'));
  167. }
  168. // 验证通过
  169. callback();
  170. };
  171. const agreementFromRules = ref<FormRules>({
  172. agreementTitle: [
  173. { required: true, trigger: 'blur', message: '请输入协议名称' },
  174. ],
  175. agreementAbbreviation: [
  176. { required: true, trigger: 'blur', message: '请输入协议简称' },
  177. ],
  178. startDate: [
  179. { required: true, trigger: 'change', message: '选择生效时间' },
  180. ],
  181. endDate: [
  182. { required: true, trigger: 'change', message: '选择失效时间' },
  183. ],
  184. withTax: [
  185. { required: true, trigger: 'change', message: '请选择是否含增值税结算' },
  186. ],
  187. moneyTime: [
  188. { required: true, trigger: 'blur', message: '请输入结算周期' },
  189. ],
  190. agreementName: [
  191. { required: true, trigger: 'blur', message: '请输入协议描述' },
  192. ],
  193. deptId: [
  194. { required: true, trigger: 'change', message: '请选择协议归属' },
  195. ],
  196. companyId: [
  197. { required: true, trigger: 'change', message: '请选择保险公司' },
  198. ],
  199. agreementType: [
  200. { required: true, trigger: 'blur', message: '请选择协议类型' },
  201. ],
  202. custodianId: [
  203. { required: true, trigger: 'blur', message: '请选择管理人' },
  204. ],
  205. dockingPerson: [
  206. { required: true, trigger: 'blur', message: '请输入对接人' },
  207. ],
  208. dockingPhone: [
  209. { required: true, trigger: 'blur', message: '请输入对接人手机号' },
  210. { validator: validatepassword, trigger: 'blur' }
  211. ],
  212. attributionId: [
  213. { required: true, trigger: 'change', message: '请选择出单账号' },
  214. ],
  215. });
  216. onBeforeMount(async () => {
  217. await loadDicts(['agreement_type', 'with_tax']);//获取多个字典
  218. getDeptTree();//归属机构
  219. company();//获取保险公司列表
  220. if (id.value) {
  221. agreementFrom.id = id.value;
  222. detailsInfo();//详情
  223. }
  224. });
  225. //协议详情
  226. const detailsInfo = () => {
  227. api.agreementApi.agreementGet(id.value).then((res: any) => {
  228. if (res.code == '200') {
  229. // 更新 agreementFrom 的属性
  230. Object.keys(agreementFrom).forEach((key) => {
  231. if (res.data.agreement.hasOwnProperty(key)) {
  232. // 使用类型断言,确保类型匹配
  233. agreementFrom[key as keyof AgreementForm] = res.data.agreement[key] as AgreementForm[keyof AgreementForm];
  234. }
  235. });
  236. } else {
  237. }
  238. });
  239. }
  240. const companyIdChange = (value: any) => {
  241. if (value) {
  242. agreementFrom.companyId = value[value.length - 1]
  243. }
  244. }
  245. const deptIdChange = (value: any) => {
  246. if (value) {
  247. agreementFrom.deptId = value[value.length - 1]
  248. }
  249. }
  250. // 禁用失效时间选择
  251. const disabledEndDate = (date: any) => {
  252. const startDate = new Date(agreementFrom.startDate);
  253. return startDate && date < startDate; // 禁用小于生效时间的日期
  254. };
  255. // 处理生效时间变化
  256. const handleStartDateChange = (value: any) => {
  257. // 如果生效时间改变,检查失效时间是否需要更新
  258. if (agreementFrom.endDate && new Date(agreementFrom.endDate) < new Date(value)) {
  259. agreementFrom.endDate = ''; // 清空失效时间
  260. }
  261. };
  262. //嫌憎编辑提交事件
  263. const submitForm = async (formEl: FormInstance | undefined) => {
  264. if (!formEl) return
  265. await formEl.validate((valid) => {
  266. if (valid) {
  267. if (id.value) {
  268. api.agreementApi.contactEdit({ ...agreementFrom }).then((res: any) => {
  269. if (res.code == '200') {
  270. ElMessage({
  271. type: 'success',
  272. message: res.msg,
  273. plain: true,
  274. })
  275. router.back()
  276. } else {
  277. }
  278. });
  279. } else {
  280. api.agreementApi.contactAdd({ ...agreementFrom }).then((res: any) => {
  281. if (res.code == '200') {
  282. ElMessage({
  283. type: 'success',
  284. message: res.msg,
  285. plain: true,
  286. })
  287. router.back()
  288. } else {
  289. }
  290. });
  291. }
  292. } else {
  293. }
  294. })
  295. }
  296. const getDeptTree = () => {
  297. api.institutionApi.institutionList({}).then((res: any) => {
  298. if (res.code == '200') {
  299. deptOptions.value = res.data;
  300. agreementFrom.deptId = res.data[0].id;
  301. } else {
  302. }
  303. });
  304. }
  305. const company = () => {
  306. api.agreementApi.findTree({ name: "" }).then((res: any) => {
  307. if (res.code == '200') {
  308. companyOptions.value = res.data;
  309. } else {
  310. ElMessage({
  311. type: 'error',
  312. message: res.msg,
  313. plain: true,
  314. })
  315. }
  316. });
  317. }
  318. //选择管理人
  319. interface managerlist {
  320. id: string,
  321. name: string,
  322. deptName: string,
  323. }
  324. const managerModalVisible = ref(false)
  325. const managerlist = ref<managerlist[]>([]);//机构向下人员列表
  326. const managerName = ref();//管理员姓名 回显使用
  327. //选中机构获取人员
  328. const managerModalNodeClick = (id: string) => {
  329. console.log(id)
  330. api.agreementApi.getUserByDeptId(id,'').then((res: any) => {
  331. if (res.code == '200') {
  332. managerlist.value = res.data;
  333. }
  334. });
  335. }
  336. const managerModalQuery=(searchValue:string)=>{
  337. api.agreementApi.getUserByDeptId('',searchValue).then((res: any) => {
  338. if (res.code == '200') {
  339. managerlist.value = res.data;
  340. }
  341. });
  342. }
  343. //选择管理人保存事件
  344. const managerModalsave = (id: string, name: string, deptName: string) => {
  345. agreementFrom.custodianId = id;
  346. managerName.value = name + ' - ' + deptName;
  347. managerModalVisible.value = false;
  348. }
  349. </script>
  350. <style lang="scss" scoped>
  351. .disabled :deep(.el-upload--picture-card) {
  352. display: none;
  353. }
  354. .agreementNotice {
  355. width: max-content;
  356. padding: 18px 24px;
  357. border: 1px solid #eee;
  358. border-radius: 4px;
  359. &:hover {
  360. background-color: #fafafa;
  361. }
  362. img {
  363. width: 40px;
  364. height: 40px;
  365. margin-right: 20px;
  366. }
  367. span:first-child {
  368. margin-bottom: 2px;
  369. font-size: 14px;
  370. color: #333;
  371. }
  372. span:last-child {
  373. font-size: 14px;
  374. color: #666;
  375. }
  376. .fileBtn {
  377. margin-left: 40px;
  378. .btn-icon {
  379. margin: 0 10px;
  380. font-size: 20px;
  381. color: #999;
  382. cursor: pointer;
  383. &:hover {
  384. color: #00a0f4;
  385. }
  386. }
  387. }
  388. }
  389. .image-view {
  390. position: absolute;
  391. top: 0;
  392. left: 0;
  393. z-index: 9999;
  394. display: flex;
  395. align-items: center;
  396. justify-content: center;
  397. width: 100%;
  398. height: 100%;
  399. background: rgb(0 0 0 / 60%);
  400. img {
  401. width: 800px;
  402. height: 800px;
  403. border-radius: 5px;
  404. }
  405. }
  406. </style>