editContract.vue 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132
  1. <script setup>
  2. import { ref,reactive,computed,watch } from "vue";
  3. import {ElMessage,ElMessageBox} from "element-plus"
  4. import { useRouter,useRoute} from 'vue-router';
  5. import _ from 'lodash'
  6. import { InfoFilled } from '@element-plus/icons-vue'
  7. import { contractInterface,customInterence } from "@/api/api.js";
  8. import{province_sorce,city_sorce} from '@/utils/distpicker';
  9. import ServiceDialog from "./components/ServiceDialog.vue"; //套餐内容弹窗组件
  10. import QyServiceTable from "./components/QyServiceTable.vue"; //权益服务内容表格组件
  11. import FiccServiceTable from "./components/FiccServiceTable.vue"; //ficc服务内容表格组件
  12. import {CalculationDate} from '@/utils/CalculationDate'
  13. const $route = useRoute()
  14. const $router = useRouter()
  15. const province_sorce_value=province_sorce
  16. const city_sorce_value=city_sorce
  17. const contractTypeDisable1=ref(false) //能否选择新签合同
  18. const contractTypeDisable2=ref(false) //能否选择续约合同
  19. const contractTypeDisable3=ref(false) //能否选择补充协议
  20. const pickerOptions=ref(null)
  21. const timeDisable=ref(false)
  22. const cusLastcontract=ref(null)
  23. const RoleType=ref(localStorage.getItem("Role") || "")
  24. const radio=ref('1')//是否有补充内容 1有 2 无
  25. const currentRouteName=ref($route.meta.title)
  26. const contractId=ref($route.query.contractId)
  27. const operationList=ref([])
  28. const formData=ref({})
  29. const formRule={
  30. ContractType: [{ required: true, message: "请选择合同类型", trigger: "change" }],
  31. timeRange: [{ required: true, message: "请选择有效期限", trigger: "change" }],
  32. OriginalPrice: [
  33. { required: true, message: "请填写合同金额", trigger: "blur" },
  34. // { pattern: /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/, message: "请输入正确的格式,可保留两位小数" },
  35. ],
  36. PayRemark: [{ required: true, message: "请填写付款方式说明", trigger: "blur" }],
  37. CompanyName: [{ required: true, message: "请填写名称", trigger: "blur" }],
  38. CreditCode: [{ required: true, message: "请填写信用码", trigger: "blur" }],
  39. Province: [{ required: true, message: "请选择地址", trigger: "change" }],
  40. Remark: [{ required: true, message: "请填写补充说明", trigger: "blur" }],
  41. PayChannel:[{ required: true, message: "请填写付款方", trigger: "change" }]
  42. }
  43. const ficcServiceData=ref([])//ficc服务内容
  44. const qyServiceData=ref([])//权益服务内容
  45. const serviceShow=ref(false)
  46. const serviceCon=ref({})//选择的服务项 查看报价单/选择品种
  47. const selectServiceData=ref([])
  48. const editValue=ref({})//修改小套餐的value
  49. const PayChannelOptions=ref([])//搜索出付款方列表
  50. watch(()=>formData.value.ContractType,(nval)=>{
  51. let obj={disabledDate() {return false}}
  52. if(cusLastcontract.value){
  53. if(nval==='续约合同'&&RoleType.value==='ficc_seller'){
  54. // ficc 起始日期为权限中最大的时间
  55. formData.value.timeRange=[]
  56. let timearr=cusLastcontract.value.map(item=> item.EndDate)
  57. let maxTime=Math.max.apply(null, timearr.map(item => (new Date(item)).getTime()));
  58. let endDate=formatDate(new Date(maxTime))
  59. console.log(endDate);
  60. obj={
  61. disabledDate(time) {
  62. return time.getTime() < new Date(endDate).getTime();
  63. }
  64. }
  65. }else{
  66. obj={
  67. disabledDate() {
  68. return false
  69. }
  70. }
  71. }
  72. if(nval==='补充协议'){
  73. let today=formatDate(new Date())
  74. // 找出权限中最晚截止的那个作为截至日期
  75. let timearr=cusLastcontract.value.map(item=> item.EndDate)
  76. let maxTime=Math.max.apply(null, timearr.map(item => (new Date(item)).getTime()));
  77. let endDate=formatDate(new Date(maxTime))
  78. formData.value.timeRange=[today,endDate]
  79. obj={disabledDate() {return true}}
  80. }
  81. }
  82. if(nval==='补充协议'){
  83. timeDisable.value=true
  84. }else{
  85. timeDisable.value=false
  86. }
  87. pickerOptions.value=obj
  88. },
  89. {immediate:true})
  90. const formItemRemark=ref(null)
  91. watch(radio,(nval, oval)=>{
  92. formItemRemark.value.resetField();
  93. if (nval === "1") {
  94. formRule.Remark[0].required = true;
  95. } else {
  96. formRule.Remark[0].required = false;
  97. }
  98. })
  99. // computed: {
  100. // pickerOptions(){
  101. // console.log('aaa');
  102. // let obj={disabledDate() {return false}}
  103. // if(this.cusLastcontract){
  104. // if(this.formData.ContractType==='续约合同'&&this.RoleType==='ficc_seller'){
  105. // // ficc 起始日期为权限中最大的时间
  106. // this.formData.timeRange=[]
  107. // let timearr=this.cusLastcontract.map(item=> item.EndDate)
  108. // let maxTime=Math.max.apply(null, timearr.map(item => (new Date(item)).getTime()));
  109. // let endDate=this.formatDate(new Date(maxTime))
  110. // obj={
  111. // disabledDate(time) {
  112. // return time.getTime() < new Date(endDate).getTime();
  113. // }
  114. // }
  115. // }else{
  116. // obj={
  117. // disabledDate() {
  118. // return false
  119. // }
  120. // }
  121. // }
  122. // if(this.formData.ContractType==='补充协议'){
  123. // let today=this.formatDate(new Date())
  124. // // 找出权限中最晚截止的那个作为截至日期
  125. // let timearr=this.cusLastcontract.map(item=> item.EndDate)
  126. // let maxTime=Math.max.apply(null, timearr.map(item => (new Date(item)).getTime()));
  127. // let endDate=this.formatDate(new Date(maxTime))
  128. // this.formData.timeRange=[today,endDate]
  129. // this.timeDisable=true
  130. // obj={disabledDate() {return true}}
  131. // }else{
  132. // this.timeDisable=false
  133. // }
  134. // }
  135. // return obj
  136. // },
  137. // },
  138. // filters
  139. // 金额转中文大写
  140. const digitUppercase=(n)=>{
  141. if (n) {
  142. n=n.toString().replace(/,/g,'')
  143. let fraction = ["角", "分"];
  144. let digit = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
  145. let unit = [
  146. ["元", "万", "亿"],
  147. ["", "拾", "佰", "仟"],
  148. ];
  149. let head = n < 0 ? "欠" : "";
  150. n = Math.abs(n);
  151. let s = "";
  152. for (let i = 0; i < fraction.length; i++) {
  153. s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, "");
  154. }
  155. // s = s || "整";
  156. n = Math.floor(n);
  157. for (let i = 0; i < unit[0].length && n > 0; i++) {
  158. let p = "";
  159. for (let j = 0; j < unit[1].length && n > 0; j++) {
  160. p = digit[n % 10] + unit[1][j] + p;
  161. n = Math.floor(n / 10);
  162. }
  163. s = p.replace(/(零.)*零$/, "").replace(/^$/, "零") + unit[0][i] + s;
  164. }
  165. return (
  166. "大写:" + (head + s.replace(/(零.)*零元/, "元").replace(/(零.)+/g, "零"))
  167. // .replace(/^整$/, "零元整")
  168. );
  169. }
  170. }
  171. //计算多少年
  172. const formateYear=(e)=>{
  173. if (!e) return;
  174. if (e[0]) {
  175. return `有效期为${CalculationDate(e[0],e[1])}`
  176. } else {
  177. return "";
  178. }
  179. }
  180. // 社会信用码变更
  181. const getContractByCode=async()=>{
  182. contractTypeDisable1.value=false
  183. contractTypeDisable2.value=false
  184. contractTypeDisable3.value=false
  185. if(!formData.value.CreditCode) return
  186. const res=await contractInterface.getContractTypeByCode({CreditCode:formData.value.CreditCode})
  187. if(res.Ret==200){
  188. let customeId=res.Data.Item&&res.Data.Item.CompanyId
  189. if(customeId){
  190. const res2=await customInterence.applyTurnContractType({CompanyId:customeId})
  191. if(res2.Ret===200){
  192. if(res2.Data.ContractType==='新签合同'){
  193. formData.value.ContractType=res2.Data.ContractType
  194. contractTypeDisable1.value=false
  195. contractTypeDisable2.value=true
  196. contractTypeDisable3.value=true
  197. }else{
  198. if(RoleType.value==='ficc_seller'){
  199. contractTypeDisable1.value=true
  200. contractTypeDisable2.value=false
  201. contractTypeDisable3.value=false
  202. }
  203. if(RoleType.value==='rai_seller'){
  204. formData.value.ContractType=res2.Data.ContractType
  205. contractTypeDisable1.value=true
  206. contractTypeDisable2.value=false
  207. contractTypeDisable3.value=true
  208. }
  209. }
  210. }
  211. }
  212. }
  213. }
  214. // 解除搜索选中的客户绑定(需求修改不需要此操作2021-9-16)
  215. const handleUnbind=()=>{
  216. ElMessageBox.confirm('此操作将解除与选择的客户绑定, 是否继续?', '提示', {
  217. confirmButtonText: '确定',
  218. cancelButtonText: '取消',
  219. type: 'warning'
  220. }).then(() => {
  221. contractTypeDisable1.value=false
  222. contractTypeDisable2.value=false
  223. contractTypeDisable3.value=false
  224. // this.pickerOptions={}
  225. cusLastcontract.value=null
  226. timeDisable.value=false
  227. }).catch(()=>{
  228. console.log('取消解绑');
  229. })
  230. }
  231. // 客户名称搜索框输入变化
  232. const handleCustomeInputChange=(e)=>{
  233. // 将付款方初始化为客户名称
  234. // const flag=this.formData.PayChannel.includes(this.formData.CompanyName)
  235. // if(!flag){
  236. // this.formData.PayChannel.push(this.formData.CompanyName)
  237. // }
  238. }
  239. // 搜索付款渠道
  240. // async querySearchAsyncPayChannel(queryString, cb){
  241. // cb([])
  242. // // if(!queryString) return
  243. // let res=await contractInterface.getPayChannel({Keyword:queryString})
  244. // if(res.Ret===200){
  245. // if(res.Data&&res.Data.length>0){
  246. // let arr=res.Data.map(item=>{
  247. // return {value:item.PayChannel,...item}
  248. // })
  249. // cb(arr)
  250. // }
  251. // }
  252. // },
  253. // 付款渠道方式修改 多选
  254. const querySearchAsyncPayChannel=async (query,type)=>{
  255. if(!type&&!query) return
  256. let res=await contractInterface.getPayChannel({Keyword:query})
  257. if(res.Ret===200){
  258. PayChannelOptions.value=res.Data||[]
  259. }
  260. }
  261. // 格式化时间
  262. const formatDate=(date)=>{
  263. let year=date.getFullYear()
  264. let month=date.getMonth()+1
  265. let day=date.getDate()
  266. return `${year}-${month<10?'0'+month:month}-${day<10?'0'+day:day}`
  267. }
  268. // 初始化客户搜索动作
  269. const initCustomeSelect=async(queryString)=>{
  270. let CompanyType=localStorage.getItem('RoleType')
  271. let res=await customInterence.customList({KeyWord:queryString,PageSize:10000,CompanyType:CompanyType,IncludeShare:true})
  272. if(res.Ret===200){
  273. if(res.Data.List&&res.Data.List.length>0){
  274. handleSelectCustome(res.Data.List[0])
  275. }
  276. }
  277. }
  278. // 客户搜索
  279. const querySearchAsyncCustome=async(queryString, cb)=>{
  280. cb([])
  281. if(!queryString) return
  282. let CompanyType=localStorage.getItem('RoleType')
  283. let res=await customInterence.customList({KeyWord:queryString,PageSize:10000,CompanyType:CompanyType,IncludeShare:true})
  284. // this.contractTypeDisable1=false
  285. // this.contractTypeDisable2=false
  286. // this.contractTypeDisable3=false
  287. // // this.pickerOptions={}
  288. // this.cusLastcontract=null
  289. // this.timeDisable=false
  290. if(res.Ret===200){
  291. if(res.Data.List.length>0){
  292. let arr=res.Data.List.map(item=>{
  293. return {value:item.CompanyName,...item}
  294. })
  295. cb(arr)
  296. }
  297. }
  298. }
  299. //选择客户
  300. const handleSelectCustome=async(item)=>{
  301. // 获取客户详情 更新表单数据
  302. let res=await customInterence.customDetail({CompanyId:item.CompanyId})
  303. if(res.Ret===200){
  304. formData.value.CreditCode=res.Data.Item.CreditCode
  305. formData.value.Province=res.Data.Item.Province
  306. formData.value.City=res.Data.Item.City
  307. }
  308. // 更新合同类型
  309. let res2=await customInterence.applyTurnContractType({CompanyId:item.CompanyId})
  310. if(res2.Ret===200){
  311. if(res2.Data.ContractType==='新签合同'){
  312. formData.value.ContractType=res2.Data.ContractType
  313. contractTypeDisable1.value=false
  314. contractTypeDisable2.value=true
  315. contractTypeDisable3.value=true
  316. }else{
  317. if(RoleType.value==='ficc_seller'){
  318. contractTypeDisable1.value=true
  319. contractTypeDisable2.value=false
  320. contractTypeDisable3.value=false
  321. }
  322. if(RoleType.value==='rai_seller'){
  323. formData.value.ContractType=res2.Data.ContractType
  324. contractTypeDisable1.value=true
  325. contractTypeDisable2.value=false
  326. contractTypeDisable3.value=true
  327. }
  328. }
  329. }
  330. // 获取客户大于今天的最后一份有效合同详情
  331. let res3=await customInterence.lastContractInfo({CompanyId:item.CompanyId})
  332. if(res3.Ret===200){
  333. if(res3.Data&&res3.Data.length>0){
  334. cusLastcontract.value=res3.Data
  335. }else{
  336. cusLastcontract.value=null
  337. }
  338. }
  339. }
  340. //判断合同期限 不小于一个月
  341. const validateTime=()=>{
  342. if(formData.value.ContractType==='补充协议') return true
  343. let start = new Date(formData.value.timeRange[0]).getTime();
  344. let end = new Date(formData.value.timeRange[1]).getTime();
  345. let oneMonth = 1000 * 60 * 60 * 24 * 29;
  346. if (end - start >= oneMonth) {
  347. return true;
  348. } else {
  349. ElMessage.warning("合同期限不能小于一个月");
  350. return false;
  351. }
  352. }
  353. //判断优惠后金额不能大于合同金额
  354. const validatePrice=()=>{
  355. if (Number(formData.value.Price) > Number(formData.value.OriginalPrice)) {
  356. ElMessage.warning("优惠后金额不得大于合同金额");
  357. return false;
  358. } else {
  359. return true;
  360. }
  361. }
  362. // 判断小套餐中是否选择品种/新增的行是否有数据
  363. const validateService=(data)=>{
  364. //判断品种列是否有值
  365. let arr = [];
  366. data.forEach((item) => {
  367. item.forEach((item2) => {
  368. if (item2.HeadName === "品种") {
  369. arr.push(...item2.ValueId);
  370. }
  371. });
  372. });
  373. // 判断行是否有值
  374. let arr2 = [];
  375. data.forEach((item, index) => {
  376. let arr = item.filter((item2) => {
  377. if (!item2.Value) return item2;
  378. });
  379. if (arr.length === item.length) {
  380. arr2.push(index);
  381. }
  382. });
  383. if (!arr.length&&formData.value.ContractType!=='补充协议') {
  384. ElMessage.warning("至少选择一个品种");
  385. return false;
  386. }
  387. if (arr2.length) {
  388. ElMessage.warning("行内至少填一项");
  389. return false;
  390. }
  391. return true;
  392. }
  393. //获取合同操作记录
  394. const getContractOperationList=()=>{
  395. contractInterface.getContractOperationList({ ContractId: contractId.value }).then((res) => {
  396. if (res.Ret === 200) {
  397. operationList.value = res.Data.List;
  398. }
  399. });
  400. }
  401. //选地地区时 选则的省份改变重置city为空
  402. const provinceChange=(e)=>{
  403. if(e.value!=formData.value.Province){
  404. // this.formData.City=''
  405. formData.value.Province=e.value
  406. }
  407. }
  408. //选择地区
  409. const selectRegion=(e)=>{
  410. formData.value.Province = e.province.value=='省'?'':e.province.value;
  411. formData.value.City = e.city.value=='市'?'':e.city.value;
  412. }
  413. // 判断套餐权限
  414. const handleValidate=(e)=>{
  415. let tag=true
  416. let tagsmall=false
  417. // ficc 补充协议 不允许有选择过的
  418. if(RoleType.value === "ficc_seller"&&e.ContractType==='补充协议'){
  419. // 是否选择大套餐 大套餐为全部品种 不能选
  420. e.Service.forEach(item=>{
  421. // 大套餐
  422. if(item.ChartPermissionId===0&&item.ServiceTemplateId===1){
  423. tag=false
  424. ElMessage.warning('FICC大套餐不可选')
  425. }
  426. // 小套餐 判断其中ficc周报是否有重复选择的权限
  427. if(item.ChartPermissionId===0&&item.ServiceTemplateId===2){
  428. let temIdarr=[]
  429. item.Detail.forEach(item2=>{
  430. item2.forEach(item3=>{
  431. if(item3.Value==='FICC周报'){
  432. item2.forEach(item4=>{
  433. if(item4.HeadName==='品种'){
  434. temIdarr=item4.ValueId
  435. }
  436. })
  437. }
  438. })
  439. })
  440. cusLastcontract.value.forEach(item4=>{
  441. if(temIdarr.indexOf(item4.ChartPermissionId)!=-1){
  442. tag=false
  443. tagsmall=true
  444. // this.$message.warning('小套餐中权限重复')
  445. }
  446. })
  447. }
  448. // 市场策略
  449. if(item.ChartPermissionId!==0){
  450. cusLastcontract.value.forEach(item2=>{
  451. if(item2.ChartPermissionId===item.ChartPermissionId){
  452. ElMessage.warning(`${item.Title}不可选`)
  453. tag=false
  454. }
  455. })
  456. }
  457. })
  458. }
  459. // 权益 续约合同
  460. if(RoleType.value === "rai_seller"&&e.ContractType==='续约合同'){
  461. const time1=new Date(formData.value.timeRange[0]).getTime()//选择的开始时间
  462. const time2=new Date(formData.value.timeRange[1]).getTime()//选择的结束时间
  463. cusLastcontract.value.forEach(item=>{
  464. const time3=new Date(item.StartDate).getTime()
  465. const time4=new Date(item.EndDate).getTime()
  466. if(time1>time4||time2<time3){
  467. console.log('选择时间和上一份无重叠');
  468. }else{
  469. console.log('时间重叠');
  470. e.Service.forEach(item2=>{
  471. console.log(item2.ChartPermissionId,item.ChartPermissionId);
  472. if(item2.ChartPermissionId===item.ChartPermissionId){
  473. ElMessage.warning('同行业有重叠的合同期限,请核实后再提交')
  474. tag=false
  475. }
  476. })
  477. }
  478. })
  479. }
  480. // 小套餐统一一个提示
  481. if(tagsmall){
  482. ElMessage.warning('小套餐中权限重复')
  483. }
  484. return tag
  485. }
  486. const formRef=ref(null)
  487. const FiccServiceTableRef=ref(null)
  488. const QyServiceTableRef=ref(null)
  489. const ServiceDialogRef=ref(null)
  490. //提交表单 存草稿、预览、提交
  491. const handleOperation=_.debounce(function(submitType) {
  492. formRef.value.validate((valid) => {
  493. if (valid) {
  494. let temarr = [];
  495. if (RoleType.value === "ficc_seller") {
  496. FiccServiceTableRef.value.tableData.forEach((item) => {
  497. let obj = {
  498. ServiceTemplateId: "",
  499. Value: "",
  500. Detail: [],
  501. Title: item.Title,
  502. ChartPermissionId:item.ChartPermissionId
  503. };
  504. obj.ServiceTemplateId = item.ServiceTemplateId;
  505. obj.Value = item.Value;
  506. if (item.selected) {
  507. //小套餐情况
  508. if (item.Detail) {
  509. if (ServiceDialogRef.value.tableHeadData.length === 0) {
  510. let arr = [];
  511. formData.value.Service.forEach((item2) => {
  512. if (item2.ServiceTemplateId === item.ServiceTemplateId) {
  513. arr = item2.DetailList.map((rowItem) => {
  514. let rowArr = [];
  515. for (let key in rowItem) {
  516. if (key.substr(0, 3) === "Col" && rowItem[key] !== "") {
  517. rowArr.push(JSON.parse(rowItem[key]));
  518. }
  519. }
  520. return rowArr;
  521. });
  522. }
  523. });
  524. obj.Detail = arr;
  525. } else {
  526. obj.Detail = [ServiceDialogRef.value.tableHeadData, ...ServiceDialogRef.value.tableData];
  527. }
  528. }
  529. temarr.push(obj);
  530. }
  531. });
  532. } else {
  533. // 只要一个分类里面 主观和客观其中一个被勾选 这个分类就要传
  534. QyServiceTableRef.value.selectAllArr.map(item =>{
  535. if(QyServiceTableRef.value.checkList.find(it => it.indexOf(item.name)!=-1 && it.indexOf("升级")==-1)){
  536. temarr.push({
  537. ServiceTemplateId: item.ServiceTemplateId,
  538. Value: item.value,
  539. Detail: null,
  540. Title: item.name,
  541. ChartPermissionId:item.ChartPermissionId
  542. })
  543. }
  544. })
  545. QyServiceTableRef.value.tableData.list.forEach((item) => {
  546. let obj = {
  547. ServiceTemplateId: "",
  548. Value: "",
  549. Detail: null,
  550. Title: item.Title,
  551. Title: item.Title == item.fatherName ? item.Title:`${item.fatherName}(${item.Title})`,
  552. ChartPermissionId:item.ChartPermissionId
  553. };
  554. obj.ServiceTemplateId = item.ServiceTemplateId;
  555. obj.Value = item.Value;
  556. let flag = ''
  557. if(item.Title == item.fatherName){
  558. //没有主客观
  559. flag= QyServiceTableRef.value.checkList.indexOf(item.Title);
  560. }else{
  561. flag= QyServiceTableRef.value.checkList.indexOf(`${item.fatherName}(${item.Title})`);
  562. }
  563. if (flag !== -1) {
  564. temarr.push(obj);
  565. }
  566. });
  567. }
  568. // 判断地址
  569. if(formData.value.Province!='海外'&&!formData.value.City){
  570. ElMessage.warning('请选择地址')
  571. return
  572. }
  573. // 判断合同期限 不小于一个月
  574. if (!validateTime()) {
  575. return;
  576. }
  577. //判断金额
  578. if (!validatePrice()) {
  579. return;
  580. }
  581. //判断是否选择了套餐
  582. if(!temarr.length){
  583. ElMessage.warning('请选择套餐')
  584. return
  585. }
  586. //判断小套餐
  587. let flag = true;
  588. temarr.forEach((item) => {
  589. if (item.Detail&&item.Detail.length) {
  590. flag = validateService(item.Detail.slice(1));
  591. }
  592. });
  593. if (!flag) return;
  594. let params = {
  595. ContractType: formData.value.ContractType,
  596. ContractBusinessType:"业务合同",
  597. StartDate: formData.value.timeRange[0],
  598. EndDate: formData.value.timeRange[1],
  599. OriginalPrice: Number(formData.value.OriginalPrice.toString().replace(/,/g,'')),
  600. Price: Number(formData.value.Price.toString().replace(/,/g,'')),
  601. PayRemark: formData.value.PayRemark,
  602. CompanyName: formData.value.CompanyName,
  603. CreditCode: formData.value.CreditCode,
  604. Province: formData.value.Province,
  605. City: formData.value.City,
  606. Address: formData.value.Address,
  607. Fax: formData.value.Fax,
  608. Phone: formData.value.Phone,
  609. Postcode: formData.value.Postcode,
  610. Remark: formData.value.Remark,
  611. PayChannel:formData.value.PayChannel.join(','),
  612. SellerRemark:formData.value.SellerRemark,
  613. TemplateId: RoleType.value === "ficc_seller" ? 1 : 2,
  614. Service: temarr,
  615. };
  616. console.log(params);
  617. // 判断套餐权限
  618. if(cusLastcontract.value&&!handleValidate(params)) return
  619. // 存草稿
  620. if(submitType==='存草稿'){
  621. handleSave(params)
  622. }
  623. //预览
  624. if(submitType==='预览'){
  625. handlePreview(params)
  626. }
  627. //提交
  628. if(submitType==='提交'){
  629. handleSubmit(params)
  630. }
  631. }else{
  632. ElMessage.warning('请完善必填项')
  633. }
  634. });
  635. },200)
  636. //存草稿
  637. const handleSave=(params)=>{
  638. let type = $route.query.type;
  639. // 复制模板(copy)
  640. if (type === "copy") {
  641. params = {
  642. SourceId: formData.value.ContractId,
  643. ...params,
  644. IsAudit: false,
  645. };
  646. contractInterface.addContract(params).then((res) => {
  647. if (res.Ret === 200) {
  648. $router.go(-1);
  649. }
  650. });
  651. }
  652. // 申请重审(applyRetrial) 修改合同(modifyConstract) 编辑(edit)修改重审(modifyAndApply)
  653. if (type === "applyRetrial" || type === "modifyConstract" || type === "edit"||type==='modifyAndApply') {
  654. params = {
  655. ContractId: formData.value.ContractId,
  656. ...params,
  657. ReAudit:false
  658. };
  659. contractInterface.editContract(params).then((res) => {
  660. if (res.Ret === 200) {
  661. $router.go(-1);
  662. }
  663. });
  664. }
  665. }
  666. //预览
  667. const handlePreview=(params)=>{
  668. contractInterface.previewContract(params).then((res) => {
  669. if (res.Ret === 200) {
  670. sessionStorage.setItem("contractdtl", res.Data.Html);
  671. let { href } = $router.resolve({ path: "/contractdtl" });
  672. window.open(href, "_blank");
  673. }
  674. });
  675. }
  676. //提交
  677. const handleSubmit=(params)=>{
  678. let type = $route.query.type;
  679. // 复制模板(copy)
  680. if (type === "copy") {
  681. params = {
  682. SourceId: formData.value.ContractId,
  683. ...params,
  684. IsAudit: true,
  685. };
  686. contractInterface.addContract(params).then((res) => {
  687. if (res.Ret === 200) {
  688. $router.go(-1);
  689. }
  690. });
  691. }
  692. // 申请重审(applyRetrial) 修改合同(modifyConstract) 编辑(edit)修改重审(modifyAndApply)
  693. if (type === "applyRetrial" || type === "modifyConstract" || type === "edit"||type==='modifyAndApply') {
  694. params = {
  695. ContractId: formData.value.ContractId,
  696. ...params,
  697. };
  698. contractInterface.editContract(params).then((res) => {
  699. if (res.Ret === 200) {
  700. $router.go(-1);
  701. }
  702. });
  703. }
  704. }
  705. //获取合同详情
  706. const getContractDetail=()=>{
  707. contractInterface.getContractDetail({ ContractId: Number(contractId.value) }).then((res) => {
  708. if (res.Ret === 200) {
  709. formData.value = { ...res.Data, timeRange: [res.Data.StartDateStr, res.Data.EndDateStr] };
  710. formData.value.PayChannel=res.Data.PayChannel.split(',')||['无']
  711. if (res.Data.Remark) {
  712. radio.value = "1";
  713. } else {
  714. radio.value = "2";
  715. }
  716. selectServiceData.value = res.Data.Service;
  717. getServiceList();
  718. initCustomeSelect(res.Data.CreditCode)
  719. }
  720. });
  721. }
  722. //获取服务套餐模板数据
  723. const getServiceList=()=>{
  724. let ProductId = RoleType.value === "ficc_seller" ? 1 : 2;
  725. contractInterface.getServiceList({ ProductId }).then((res) => {
  726. if (res.Ret === 200) {
  727. if (RoleType.value === "ficc_seller") {
  728. ficcServiceData.value = res.Data;
  729. } else {
  730. qyServiceData.value = res.Data;
  731. }
  732. }
  733. });
  734. }
  735. //小套餐点击保存 更新数据
  736. const serviceSave=(e)=>{
  737. editValue.value = { ServiceTemplateId: e.ServiceTemplateId, Value: e.Value, tableData: e.tableData, tableHeadData: e.tableHeadData };
  738. // this.ficcServiceData.forEach((item) => {
  739. // if (item.ServiceTemplateId === e.ServiceTemplateId) {
  740. // item.Value = e.Value;
  741. // }
  742. // });
  743. // this.selectServiceData.forEach((item) => {
  744. // if (item.ServiceTemplateId === e.ServiceTemplateId) {
  745. // item.Value = e.Value;
  746. // }
  747. // });
  748. }
  749. //显示查看报价单弹窗
  750. const handleShowService=(e)=>{
  751. serviceCon.value = e;
  752. serviceShow.value = true;
  753. }
  754. //关闭查看报价单弹窗
  755. const serviceClose=()=>{
  756. serviceShow.value = false;
  757. }
  758. // 金额输入框获取焦点
  759. const handlePriceBoxFocus=(key)=>{
  760. let val=formData.value[key].toString()
  761. val=val.replace(/,/g,'')
  762. formData.value[key]=val
  763. }
  764. // 金额输入框获失去焦点
  765. const handlePriceBoxBlur=(key)=>{
  766. let str=formData.value[key].toString()
  767. let num1='',num2=''
  768. if(str.indexOf(".")!=-1){
  769. num1=str.substring(0,str.indexOf("."))
  770. num2=str.substring(str.length,str.indexOf("."))
  771. if(Number(num2)<=0){
  772. num2=''
  773. }
  774. }else{
  775. num1=str
  776. }
  777. formData.value[key]=num1.replace(/(?!^)(?=(\d{3})+$)/g, ',')+num2
  778. }
  779. getContractDetail();
  780. getContractOperationList();
  781. </script>
  782. <template>
  783. <div class="flex addconstract-container">
  784. <el-form ref="formRef" :model="formData" label-position="left" :rules="formRule" label-width="110px" style="width: 80%"
  785. size="large">
  786. <section class="section">
  787. <h2 class="section-title">客户信息</h2>
  788. <div class="section-container">
  789. <div class="flex border-top" style="padding-top: 30px">
  790. <el-form-item label="甲方名称" prop="CompanyName" style="width: 50%">
  791. <!-- <el-input v-model="formData.CompanyName" placeholder="请输入名称" style="width: 350px"></el-input> -->
  792. <el-autocomplete
  793. v-model="formData.CompanyName"
  794. :fetch-suggestions="querySearchAsyncCustome"
  795. placeholder="请输入或者搜索客户名称"
  796. @select="handleSelectCustome"
  797. @blur="handleCustomeInputChange"
  798. style="width: 50%"
  799. ></el-autocomplete>
  800. </el-form-item>
  801. <el-form-item label="社会信用码" prop="CreditCode" style="width: 50%">
  802. <el-input v-model="formData.CreditCode" placeholder="请输入社会信用码" style="width: 350px" :disabled="cusLastcontract" @input="getContractByCode"></el-input>
  803. <!-- <span style="font-size:14px;color:#4099ef;cursor: pointer;" v-if="cusLastcontract" @click="handleUnbind">解除绑定</span> -->
  804. </el-form-item>
  805. </div>
  806. <div class="flex border-top" style="padding-top: 30px">
  807. <el-form-item label="公司地址" prop="Province" style="width: 50%">
  808. <v-distpicker :province-source="province_sorce_value"
  809. :city-source="city_sorce_value" :province="formData.Province" :city="formData.City" hide-area @province="provinceChange" @selected="selectRegion"></v-distpicker>
  810. </el-form-item>
  811. <el-form-item label="详细地址" prop="address" style="width: 50%">
  812. <el-input v-model="formData.Address" placeholder="请输入详细地址" style="width: 350px"></el-input>
  813. </el-form-item>
  814. </div>
  815. <div class="flex border-top" style="padding-top: 30px">
  816. <el-form-item label="传真" prop="customeCz" style="width: 50%">
  817. <el-input v-model="formData.Fax" placeholder="请输入传真" style="width: 350px"></el-input>
  818. </el-form-item>
  819. <el-form-item label="电话" prop="customeTel" style="width: 50%">
  820. <el-input v-model="formData.Phone" placeholder="请输入电话" style="width: 350px"></el-input>
  821. </el-form-item>
  822. </div>
  823. <el-form-item label="邮编" prop="postCode" class="border-top">
  824. <el-input v-model="formData.Postcode" placeholder="请输入邮编" style="width: 350px"></el-input>
  825. </el-form-item>
  826. </div>
  827. </section>
  828. <section class="section">
  829. <h2 class="section-title">合同信息</h2>
  830. <div class="section-container">
  831. <div class="flex border-top" style="padding-top: 30px">
  832. <el-form-item label="合同编号" style="width: 50%">
  833. <span>{{ formData.ContractCode }}</span>
  834. </el-form-item>
  835. <el-form-item label="合同归属" style="width: 50%">
  836. <span>{{ formData.ProductId === 1 ? "FICC" : "权益" }}</span>
  837. </el-form-item>
  838. </div>
  839. <el-form-item label="合同类型" prop="ContractType" class="border-top">
  840. <el-radio-group v-model="formData.ContractType">
  841. <div style="display:flex">
  842. <div style="margin-right:10px;">
  843. <el-radio label="新签合同" :disabled="contractTypeDisable1">新签合同</el-radio>
  844. <el-tooltip effect="dark" style="cursor: pointer;width:20px;">
  845. <template #content>没有正式转试用记录的客户,在申请转正时提交的合同</template>
  846. <el-icon :size="16" style="margin-left:-20px"><InfoFilled /></el-icon>
  847. </el-tooltip>
  848. </div>
  849. <div style="margin-right:10px">
  850. <el-radio label="续约合同" :disabled="contractTypeDisable2">续约合同</el-radio>
  851. <el-tooltip effect="dark" style="cursor: pointer;width:20px;">
  852. <template #content>
  853. 1、有正式转试用记录的客户,在申请转正时提交的合同<br>
  854. 2、所有客户在续约申请时提交的合同
  855. </template>
  856. <el-icon :size="16" style="margin-left:-20px"><InfoFilled /></el-icon>
  857. </el-tooltip>
  858. </div>
  859. <div style="margin-right:10px" v-if="RoleType!=='rai_seller'">
  860. <el-radio label="补充协议" :disabled="contractTypeDisable3">补充协议</el-radio>
  861. </div>
  862. </div>
  863. </el-radio-group>
  864. </el-form-item>
  865. <div class="flex border-top">
  866. <el-form-item label="合同期限" prop="timeRange" style="width: 50%">
  867. <el-date-picker
  868. style="max-width: 350px;"
  869. v-model="formData.timeRange"
  870. type="daterange"
  871. value-format="yyyy-MM-dd"
  872. range-separator="至"
  873. start-placeholder="开始日期"
  874. end-placeholder="结束日期"
  875. :disabled="timeDisable"
  876. :picker-options="pickerOptions">
  877. </el-date-picker>
  878. </el-form-item>
  879. <span style="line-height: 40px">{{ formateYear(formData.timeRange) }}</span>
  880. </div>
  881. <div class="flex border-top">
  882. <el-form-item label="合同金额" prop="OriginalPrice" style="width: 50%">
  883. <el-input v-model="formData.OriginalPrice" @focus="handlePriceBoxFocus('OriginalPrice')" @blur="handlePriceBoxBlur('OriginalPrice')" placeholder="请输入合同金额" style="width: 220px"></el-input>
  884. </el-form-item>
  885. <span style="line-height: 40px">{{ digitUppercase(formData.OriginalPrice) }}</span>
  886. </div>
  887. <div class="flex border-top">
  888. <el-form-item label="优惠后金额" prop="Price" style="width: 50%">
  889. <el-input v-model="formData.Price" @focus="handlePriceBoxFocus('Price')" @blur="handlePriceBoxBlur('Price')" placeholder="请输入优惠后金额" style="width: 220px"></el-input>
  890. </el-form-item>
  891. <span style="line-height: 40px">{{ digitUppercase(formData.Price) }}</span>
  892. </div>
  893. <el-form-item label="付款方式说明" prop="PayRemark" class="border-top">
  894. <el-input type="textarea" v-model="formData.PayRemark" placeholder="请输入付款方式说明(请参考以下说明模板填写,请勿填写现金/转账等支付形式)" style="width: 80%"></el-input>
  895. <p>说明模板:甲方自合同生效日起的十日之内一次性支付一年服务费,乙方收款后为甲方开具合法有效的增值税发票。</p>
  896. </el-form-item>
  897. <el-form-item label="付款方" prop="PayChannel" class="border-top">
  898. <!-- <el-input type="textarea" v-model="formData.PayChannel" placeholder="填写代支付的券商名称/期货公司名称,若非代付填写无" style="width: 80%"></el-input> -->
  899. <!-- <el-autocomplete
  900. v-model="formData.PayChannel"
  901. :fetch-suggestions="querySearchAsyncPayChannel"
  902. placeholder="请输入"
  903. style="width: 80%"
  904. ></el-autocomplete> -->
  905. <el-select
  906. v-model="formData.PayChannel"
  907. multiple
  908. filterable
  909. remote
  910. allow-create
  911. placeholder="请输入关键词"
  912. :remote-method="querySearchAsyncPayChannel"
  913. style="width: 80%">
  914. <el-option
  915. v-for="item in PayChannelOptions"
  916. :key="item.PayChannel"
  917. :label="item.PayChannel"
  918. :value="item.PayChannel">
  919. </el-option>
  920. </el-select>
  921. <p>如果为代付,则需要填写代付方名称(期货公司或者证券公司),请勿填写现金/转账</p>
  922. </el-form-item>
  923. <!-- <el-form-item label="备注" prop="SellerRemark" class="border-top">
  924. <el-input type="textarea" v-model="formData.SellerRemark" placeholder="审批人查看,不在生成合同中展示" style="width: 80%"></el-input>
  925. </el-form-item> -->
  926. </div>
  927. </section>
  928. <section class="section">
  929. <h2 class="section-title">服务内容</h2>
  930. <div class="section-container">
  931. <!-- ficc 服务内容表格 -->
  932. <FiccServiceTable
  933. ref="FiccServiceTableRef"
  934. :canEdit="true"
  935. :serviceData="ficcServiceData"
  936. :hasSercive="selectServiceData"
  937. :editValue="editValue"
  938. :contractType="formData.ContractType"
  939. :isEdit="true"
  940. @handleShowService="handleShowService"
  941. v-if="RoleType === 'ficc_seller'"
  942. ></FiccServiceTable>
  943. <!-- 权益 服务内容表格 -->
  944. <QyServiceTable ref="QyServiceTableRef" :canEdit="true" :serviceData="qyServiceData" :hasSercive="selectServiceData" @handleShowService="handleShowService" v-else></QyServiceTable>
  945. </div>
  946. <p style="margin-top: 30px; margin-bottom: 20px">补充内容(eg额外赠送、路演次数规定)</p>
  947. <el-radio v-model="radio" label="2">无</el-radio>
  948. <el-radio v-model="radio" label="1">有</el-radio>
  949. <el-form-item prop="Remark" label-width="0" ref="formItemRemark">
  950. <el-input v-if="radio === '1'" type="textarea" v-model="formData.Remark" rows="5" placeholder="请输入内容" style="margin: 20px 0; display: block; box-sizing: border-box"></el-input>
  951. </el-form-item>
  952. </section>
  953. <section class="section">
  954. <h2 class="section-title">审批备注</h2>
  955. <div class="section-container">
  956. <el-form-item label="备注" prop="SellerRemark" class="border-top">
  957. <el-input type="textarea" v-model="formData.SellerRemark" placeholder="请输入备注(仅供审批人查看,不在生成合同中展示)" style="width: 80%"></el-input>
  958. </el-form-item>
  959. </div>
  960. </section>
  961. </el-form>
  962. <div class="right-wrap">
  963. <div style="text-align: center" v-if="currentRouteName === '编辑合同' || currentRouteName === '复制模板'||currentRouteName === '重审合同'||currentRouteName === '修改重审'">
  964. <el-button type="primary" plain style="width: 30%;min-width:70px;margin-bottom:10px" @click="handleOperation('存草稿')" size="large">存草稿</el-button>
  965. <el-button type="primary" style="width: 30%;margin-left:3%;min-width:70px;margin-bottom:10px" @click="handleOperation('预览')" size="large">预览</el-button>
  966. <el-button type="primary" style="width: 30%;margin-left:3%;min-width:70px;margin-bottom:10px" @click="handleOperation('提交')" size="large">提交</el-button>
  967. </div>
  968. <!-- <div style="text-align: center" v-if="currentRouteName === '重审合同'">
  969. <el-button type="primary" plain style="width: 30%;min-width:70px;margin-bottom:10px" @click="handleSave">存草稿</el-button>
  970. <el-button type="primary" style="width: 30%;min-width:70px" @click="handlePreview">预览</el-button>
  971. <el-button type="primary" style="width: 30%;min-width:70px" @click="handleSubmit">提交</el-button>
  972. </div> -->
  973. <div class="timeline-wrap">
  974. <el-timeline>
  975. <el-timeline-item color="#409EFF" v-for="item in operationList" :key="item.Id" placement="top" :timestamp="item.CreateTimeStr"> {{ item.OpUserName }}{{ item.Remark }} </el-timeline-item>
  976. </el-timeline>
  977. </div>
  978. </div>
  979. <!-- 套餐 -->
  980. <ServiceDialog ref="ServiceDialogRef" :serviceShow="serviceShow" @serviceClose="serviceClose" @serviceSave="serviceSave" :serviceCon="serviceCon"></ServiceDialog>
  981. </div>
  982. </template>
  983. <style>
  984. .el-radio__input.is-checked .el-radio__inner {
  985. background-color: transparent;
  986. }
  987. .el-radio__inner::after {
  988. width: 6px;
  989. height: 6px;
  990. background-color: #409eff;
  991. }
  992. .el-checkbox__label {
  993. font-size: 16px !important;
  994. }
  995. .el-form-item {
  996. margin-bottom: 30px;
  997. }
  998. .el-input.is-disabled .el-input__inner {
  999. color: #606266;
  1000. }
  1001. .el-radio__input.is-disabled + span.el-radio__label {
  1002. color: #606266;
  1003. }
  1004. .el-range-editor.is-disabled input {
  1005. color: #606266;
  1006. }
  1007. .el-textarea.is-disabled .el-textarea__inner {
  1008. color: #606266;
  1009. }
  1010. .el-timeline-item__tail {
  1011. border-left: 2px solid #409eff;
  1012. }
  1013. </style>
  1014. <style lang="scss" scoped>
  1015. .addconstract-container {
  1016. min-height: calc(100vh - 250px);
  1017. position: relative;
  1018. font-size: 16px;
  1019. color: #000;
  1020. }
  1021. .flex {
  1022. display: flex;
  1023. }
  1024. .section {
  1025. background-color: #fff;
  1026. border: 1px solid #aab4cc;
  1027. border-radius: 4px;
  1028. padding: 20px;
  1029. margin-bottom: 20px;
  1030. .section-title {
  1031. margin-bottom: 30px;
  1032. }
  1033. .border-top {
  1034. padding-top: 30px;
  1035. border-top: 1px solid #dcdfe6;
  1036. }
  1037. }
  1038. .right-wrap {
  1039. margin-left: 20px;
  1040. flex: 1;
  1041. .timeline-wrap {
  1042. margin-top: 10px;
  1043. background-color: #fff;
  1044. border: 1px solid #aab4cc;
  1045. padding: 20px;
  1046. border-radius: 4px;
  1047. text-align: left;
  1048. height: calc(100% - 120px);
  1049. max-height: 1130px;
  1050. overflow-y: auto;
  1051. }
  1052. }
  1053. </style>