89 changed files with 622 additions and 5349 deletions
			
			
		
								
									
										File diff suppressed because one or more lines are too long
									
								
							
						
					| @ -1,167 +0,0 @@ | |||||
| /** |  | ||||
|  * 评级等级下拉选项数组 |  | ||||
|  */ |  | ||||
| export const RatingLevelOptions = [ |  | ||||
|   { label: 'AAA+', value: 'AAA+', numberValue: 15, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'AAA', value: 'AAA', numberValue: 14, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'AA+', value: 'AA+', numberValue: 13, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'AA', value: 'AA', numberValue: 12, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'AA-', value: 'AA-', numberValue: 11, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'A+', value: 'A+', numberValue: 10, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'A', value: 'A', numberValue: 9, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'A-', value: 'A-', numberValue: 8, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'BBB', value: 'BBB', numberValue: 7, color: 'green', denseLabel: false }, |  | ||||
|   { label: 'BB', value: 'BB', numberValue: 6, color: 'red', denseLabel: false }, |  | ||||
|   { label: 'B', value: 'B', numberValue: 5, color: 'red', denseLabel: false }, |  | ||||
|   { label: 'CCC', value: 'CCC', numberValue: 4, color: 'red', denseLabel: false }, |  | ||||
|   { label: 'CC', value: 'CC', numberValue: 3, color: 'red', denseLabel: false }, |  | ||||
|   { label: 'C', value: 'C', numberValue: 2, color: 'red', denseLabel: false }, |  | ||||
|   { label: 'D', value: 'D', numberValue: 1, color: 'red', denseLabel: false }, |  | ||||
| ]; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 评级步骤对象 |  | ||||
|  */ |  | ||||
| export const RatingStep = { |  | ||||
|   CSWC: 'INIT_FINISH', // 初始化完成
 |  | ||||
|   KHXX: 'CUST_INFO', // 客户信息
 |  | ||||
|   DLFX: 'QUANTITATIVE', // 定量分析
 |  | ||||
|   DXFX: 'QUALITATIVE_EDIT', // 定性分析
 |  | ||||
|   CPJG: 'QUALITATIVE_SHOW', // 初评结果
 |  | ||||
|   PJTZX: 'ADJUST_ITEM', // 评级调整项
 |  | ||||
|   QSYJ: 'OTHER', // 签署意见
 |  | ||||
|   PJBG: 'REPORT_INFO', // 评级报告
 |  | ||||
| }; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 评级流程状态对象 |  | ||||
|  */ |  | ||||
| export const RatingProcessStatus = { |  | ||||
|   AWAIT_RATING: 'AWAIT_RATING', // 待评级
 |  | ||||
|   AWAIT_SUBMIT: 'AWAIT_SUBMIT', // 待提交
 |  | ||||
|   BACK: 'BACK', // 退回
 |  | ||||
|   APPROVALING: 'APPROVALING', // 审批中
 |  | ||||
|   PASS: 'PASS', // 通过
 |  | ||||
|   NEGATIVED: 'NEGATIVED', // 否决
 |  | ||||
|   END: 'END', // 已结束
 |  | ||||
| }; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 评级流程操作 |  | ||||
|  */ |  | ||||
| export const RatingProcessOperationStatus = [ |  | ||||
|   { |  | ||||
|     label: '提交', |  | ||||
|     value: '10', |  | ||||
|   }, |  | ||||
|   { |  | ||||
|     label: '否决', |  | ||||
|     value: '20', |  | ||||
|   }, |  | ||||
|   { |  | ||||
|     label: '退回', |  | ||||
|     value: '30', |  | ||||
|   }, |  | ||||
|   { |  | ||||
|     label: '撤销', |  | ||||
|     value: '40', |  | ||||
|   }, |  | ||||
|   { |  | ||||
|     label: '批准', |  | ||||
|     value: '50', |  | ||||
|   }, |  | ||||
|   { |  | ||||
|     label: '同意', |  | ||||
|     value: '60', |  | ||||
|   }, |  | ||||
|   { |  | ||||
|     label: '不同意', |  | ||||
|     value: '70', |  | ||||
|   }, |  | ||||
| ]; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 评级流程操作标识 |  | ||||
|  */ |  | ||||
| export const RatingProcessOperation = { |  | ||||
|   // 通过
 |  | ||||
|   APPROVE: 1, |  | ||||
|   // 否决
 |  | ||||
|   REJECT: 2, |  | ||||
|   // 同意
 |  | ||||
|   AGREE: 4, |  | ||||
|   // 不同意
 |  | ||||
|   DISAGREE: 5, |  | ||||
|   // 提交下一步
 |  | ||||
|   SUBMIT: 6, |  | ||||
|   // 提交到其他上级(信审会)
 |  | ||||
|   UPPER_1: 8, |  | ||||
|   // 提交到上级
 |  | ||||
|   UPPER: 9, |  | ||||
|   //退回起始步骤
 |  | ||||
|   BACK_START: -1, |  | ||||
|   //退回到某步骤
 |  | ||||
|   BACK: -2, |  | ||||
| }; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 违约认定流程状态对象 |  | ||||
|  */ |  | ||||
| export const DefaultProcessStatus = { |  | ||||
|   PASS: '03', // 通过
 |  | ||||
| }; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 选择客户标记 |  | ||||
|  */ |  | ||||
| export const SelectCustomerFlag = { |  | ||||
|   RATING: 'rating', // 发起评级
 |  | ||||
|   COGNIZANCE: 'cognizance', // 违约认定申请
 |  | ||||
| }; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 财报类型对象 |  | ||||
|  */ |  | ||||
| export const FinanceReportType = { |  | ||||
|   QYL: '1', // 企业类
 |  | ||||
|   SYL: '2', // 事业类
 |  | ||||
| }; |  | ||||
| 
 |  | ||||
| /** |  | ||||
|  * 财报科目类型对象 |  | ||||
|  */ |  | ||||
| export const FinanceReportProjectType = { |  | ||||
|   QYLZCFZ: '01', // 企业类资产负债
 |  | ||||
|   QYLXJL: '02', // 企业类现金流
 |  | ||||
|   QYLSY: '03', // 企业类损益
 |  | ||||
|   SYLZCFZ: '11', // 事业类资产负债
 |  | ||||
|   SYLSRZC: '12', // 事业类收入支出表
 |  | ||||
| }; |  | ||||
| 
 |  | ||||
| export const Round = (val: any, precision) => { |  | ||||
|   if (typeof precision !== 'number' || precision <= 0) return val; |  | ||||
|   let result = val; |  | ||||
|   if (val && typeof val === 'string') { |  | ||||
|     const patt = /^-?[0-9]+.?[0-9]*/; |  | ||||
|     if (patt.test(val)) { |  | ||||
|       result = parseFloat(val); |  | ||||
|     } |  | ||||
|   } |  | ||||
|   if (result && typeof result === 'number' && String(result).indexOf('.') > -1) { |  | ||||
|     let scale = '1'; |  | ||||
|     for (let i = 0; i < precision; i++) { |  | ||||
|       scale += 0; |  | ||||
|     } |  | ||||
|     const pre = 'e' + precision; |  | ||||
|     const post = 'e-' + precision; |  | ||||
|     return (+(Math.round(result + pre) + post)).toFixed(precision); |  | ||||
|   } |  | ||||
|   return result; |  | ||||
| }; |  | ||||
| 
 |  | ||||
| export const RatioFormat = (val) => { |  | ||||
|   if (val && typeof val === 'number') { |  | ||||
|     return Round(val * 100, 2) + '%'; |  | ||||
|   } |  | ||||
|   return val; |  | ||||
| }; |  | ||||
| @ -1,218 +0,0 @@ | |||||
| <template> |  | ||||
|   <div style="height: 100%"> |  | ||||
|     <w-grid |  | ||||
|       ref="companyRatingGridRef" |  | ||||
|       title="客户评级列表" |  | ||||
|       :data-url="Environment.apiContextPath('api/irbs/companyRating')" |  | ||||
|       :fetch-data-url="Environment.apiContextPath('api/irbs/companyRating/query')" |  | ||||
|       :sort-no="true" |  | ||||
|       group-mode="alone" |  | ||||
|       :checkbox-selection="false" |  | ||||
|       :query-form-cols-num="4" |  | ||||
|       :query-form-fields="companyRatingGrid.queryFormFields" |  | ||||
|       :columns="companyRatingGrid.columns" |  | ||||
|       :toolbar-actions="companyRatingGrid.buttons" |  | ||||
|       :query-criteria="{ |  | ||||
|         operator: 'and', |  | ||||
|         criteria: [ |  | ||||
|           { |  | ||||
|             fieldName: 'triggerType', |  | ||||
|             operator: 'equals', |  | ||||
|             value: 'INDEPENDENT', |  | ||||
|           }, |  | ||||
|           { |  | ||||
|             fieldName: 'launchUser', |  | ||||
|             operator: 'equals', |  | ||||
|             value: SessionManager.getUser().loginName, |  | ||||
|           }, |  | ||||
|         ], |  | ||||
|       }" |  | ||||
|       :sort-by="['-createDate']" |  | ||||
|     ></w-grid> |  | ||||
|     <LaunchRatingDialog ref="launchRatingdialogRef" :dictionary="dictionary" @refresh="refreshTable"></LaunchRatingDialog> |  | ||||
|     <RatingDialog ref="ratingdialogRef" @refresh="refreshTable"></RatingDialog> |  | ||||
|     <GrayModelDialog ref="grayDialogRef" @refresh="refreshTable"></GrayModelDialog> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, shallowRef } from 'vue'; |  | ||||
| import { useQuasar } from 'quasar'; |  | ||||
| import { Environment, EnumTools, DictionaryTools, Options, Formater, axios, NotifyManager, Tools, SessionManager } from 'platform-core'; |  | ||||
| import LaunchRatingDialog from './LaunchRatingDialog.vue'; |  | ||||
| import RatingDialog from './RatingDialog.vue'; |  | ||||
| import GrayModelDialog from './GrayModelDialog.vue'; |  | ||||
| import { RatingLevelOptions, RatingProcessStatus, Round } from './CustRating.ts'; |  | ||||
| import RatingLevel from './RatingLevel.vue'; |  | ||||
| 
 |  | ||||
| const $q = useQuasar(); |  | ||||
| const companyRatingGridRef = ref(); |  | ||||
| const launchRatingdialogRef = ref(); |  | ||||
| const ratingdialogRef = ref(); |  | ||||
| const grayDialogRef = ref(); |  | ||||
| 
 |  | ||||
| const RatingStatusEnum = await EnumTools.fetch('irbs.cust.rating.enums.RatingStatus'); |  | ||||
| const RatingProcessStatusEnum = await EnumTools.fetch('irbs.cust.rating.enums.RatingProcessStatus'); |  | ||||
| const dictCustomerTypeCd = await DictionaryTools.fetch('CustomerTypeCd'); |  | ||||
| const optionsCustomerTypeCd = Options.dictionary(dictCustomerTypeCd); |  | ||||
| const dictCustomerSizeCd = await DictionaryTools.fetch('CustomerSizeCd'); |  | ||||
| const optionsCustomerSizeCd = Options.dictionary(dictCustomerSizeCd); |  | ||||
| 
 |  | ||||
| const dictionary = { |  | ||||
|   dictCustomerTypeCd: dictCustomerTypeCd, |  | ||||
|   optionsCustomerTypeCd: optionsCustomerTypeCd, |  | ||||
|   dictCustomerSizeCd: dictCustomerSizeCd, |  | ||||
|   optionsCustomerSizeCd: optionsCustomerSizeCd, |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const companyRatingGrid = { |  | ||||
|   buttons: [ |  | ||||
|     'query', |  | ||||
|     'reset', |  | ||||
|     'separator', |  | ||||
|     { |  | ||||
|       extend: 'add', |  | ||||
|       label: '发起评级', |  | ||||
|       click: () => { |  | ||||
|         launchRatingdialogRef.value.show(); |  | ||||
|       }, |  | ||||
|     }, |  | ||||
|     { |  | ||||
|       extend: 'edit', |  | ||||
|       label: '评级', |  | ||||
|       enableIf: (args) => { |  | ||||
|         if ( |  | ||||
|           args.selected && |  | ||||
|           (args.selected['processStatus'] === RatingProcessStatus.AWAIT_RATING || |  | ||||
|             args.selected['processStatus'] === RatingProcessStatus.AWAIT_SUBMIT || |  | ||||
|             args.selected['processStatus'] === RatingProcessStatus.BACK) |  | ||||
|         ) { |  | ||||
|           return true; |  | ||||
|         } |  | ||||
|         return false; |  | ||||
|       }, |  | ||||
|       click: (args) => { |  | ||||
|         ratingdialogRef.value.show(args.selected); |  | ||||
|       }, |  | ||||
|     }, |  | ||||
|     // { |  | ||||
|     //   extend: 'remove', |  | ||||
|     //   label: '撤销', |  | ||||
|     //   click: () => {}, |  | ||||
|     // }, |  | ||||
|     'separator', |  | ||||
|     { |  | ||||
|       extend: 'view', |  | ||||
|       click: (args) => { |  | ||||
|         ratingdialogRef.value.show(args.selected, true); |  | ||||
|       }, |  | ||||
|     }, |  | ||||
|     'export', |  | ||||
|     'separator', |  | ||||
|     [ |  | ||||
|       { |  | ||||
|         name: 'otherOp', |  | ||||
|         label: '其他操作', |  | ||||
|         icon: 'device_hub', |  | ||||
|       }, |  | ||||
|       { |  | ||||
|         name: 'viewGray', |  | ||||
|         extend: 'view', |  | ||||
|         label: '查看灰度模型结果', |  | ||||
|         click: (args) => { |  | ||||
|           grayDialogRef.value.show(args.selected); |  | ||||
|         }, |  | ||||
|       }, |  | ||||
|       'separator', |  | ||||
|       { |  | ||||
|         extend: 'remove', |  | ||||
|         name: 'delete', |  | ||||
|         label: '强制删除', |  | ||||
|         click: (args) => { |  | ||||
|           // args._click(); |  | ||||
|           $q.dialog({ |  | ||||
|             title: '询问', |  | ||||
|             message: '是否确认删除已生成评级信息及流程信息?', |  | ||||
|             cancel: { noCaps: true }, |  | ||||
|             ok: { noCaps: true }, |  | ||||
|             persistent: true, |  | ||||
|           }).onOk(() => { |  | ||||
|             axios |  | ||||
|               .post(Environment.apiContextPath('api/irbs/companyRating/removeRatingAndProcess/' + args.selected['id'])) |  | ||||
|               .then((resp) => { |  | ||||
|                 if (resp && resp.data) { |  | ||||
|                   NotifyManager.info('删除成功'); |  | ||||
|                   companyRatingGridRef.value.refresh(); |  | ||||
|                 } |  | ||||
|               }) |  | ||||
|               .catch((error) => { |  | ||||
|                 console.info('error====', error); |  | ||||
|                 NotifyManager.warn('删除失败'); |  | ||||
|               }); |  | ||||
|           }); |  | ||||
|         }, |  | ||||
|       }, |  | ||||
|     ], |  | ||||
|     'separator', |  | ||||
|   ], |  | ||||
|   queryFormFields: [ |  | ||||
|     { label: '申请编号', name: 'id', type: 'w-text' }, |  | ||||
|     { label: '客户号', name: 'custNo', type: 'w-text' }, |  | ||||
|     { label: '客户名称', name: 'custName', type: 'w-text' }, |  | ||||
|     { |  | ||||
|       label: '认定等级', |  | ||||
|       name: 'finalLevel', |  | ||||
|       type: 'w-select', |  | ||||
|       options: RatingLevelOptions, |  | ||||
|     }, |  | ||||
|     { label: '流程状态', name: 'processStatus', type: 'w-select', options: Options.enum(RatingProcessStatusEnum) }, |  | ||||
|     { label: '评级状态', name: 'ratingStatus', type: 'w-select', options: Options.enum(RatingStatusEnum) }, |  | ||||
|   ], |  | ||||
|   columns: [ |  | ||||
|     { name: 'id', label: '申请编号', align: 'center' }, |  | ||||
|     { name: 'custNo', label: '客户号', align: 'center' }, |  | ||||
|     { name: 'custName', label: '客户名称', width: 150 }, |  | ||||
|     { name: 'industryTypeName', label: '行业类型' }, |  | ||||
|     { name: 'modelScore', label: '模型得分' }, |  | ||||
|     { name: 'modelLevel', label: '模型等级' }, |  | ||||
|     { name: 'adjLevel', label: '调整后等级' }, |  | ||||
|     { name: 'initLevel', label: '初评等级' }, |  | ||||
|     { |  | ||||
|       name: 'finalLevel', |  | ||||
|       label: '认定等级', |  | ||||
|       format: (val) => { |  | ||||
|         if (!Tools.isEmpty(val)) { |  | ||||
|           return { |  | ||||
|             componentType: RatingLevel, |  | ||||
|             attrs: { |  | ||||
|               level: val, |  | ||||
|               dense: true, |  | ||||
|             }, |  | ||||
|           }; |  | ||||
|         } |  | ||||
|         return val; |  | ||||
|       }, |  | ||||
|     }, |  | ||||
|     { |  | ||||
|       name: 'pd', |  | ||||
|       label: '违约概率', |  | ||||
|       format: (val) => { |  | ||||
|         if (val && typeof val === 'number') { |  | ||||
|           return Round(val * 100, 2) + '%'; |  | ||||
|         } |  | ||||
|         return val; |  | ||||
|       }, |  | ||||
|     }, |  | ||||
|     { name: 'effectiveTime', label: '评级生效日', format: Formater.dateOnly() }, |  | ||||
|     { name: 'matureTime', label: '评级失效日', format: Formater.dateOnly() }, |  | ||||
|     { name: 'ratingStatus', label: '评级状态', format: Formater.enum(RatingStatusEnum) }, |  | ||||
|     { name: 'launchUser', label: '发起人' }, |  | ||||
|     { name: 'processStatus', label: '流程状态', format: Formater.enum(RatingProcessStatusEnum) }, |  | ||||
|     { name: 'currentAssignee', label: '当前处理人' }, |  | ||||
|   ], |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const refreshTable = () => { |  | ||||
|   companyRatingGridRef.value.refresh(); |  | ||||
| }; |  | ||||
| </script> |  | ||||
| @ -1,5 +0,0 @@ | |||||
| <template> |  | ||||
|   <div>111</div> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"></script> |  | ||||
| @ -1,5 +0,0 @@ | |||||
| <template> |  | ||||
|   <div>111</div> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"></script> |  | ||||
| @ -1,349 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-dialog ref="dialogRef" :title="state.dialogTitle" width="80%" height="80%" body-padding="0px 0px 0px 0px" :maximized="true" :buttons="[]"> |  | ||||
|     <div> |  | ||||
|       <div class="p-[10px]"> |  | ||||
|         <span class="text-3xl text-amber-600" |  | ||||
|           >{{ state.custInfoObj['custName'] }}<q-badge v-if="state.custInfoObj['marketEnterprisesInd'] === '1'" color="red" align="top">上市</q-badge></span |  | ||||
|         > |  | ||||
|         <div class="flex pt-2"> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>客户号</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ state.custInfoObj['custNo'] }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>企业规模</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictCustomerSize)(state.custInfoObj['customerSize']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>企业类型</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictRegisteredType)(state.custInfoObj['registeredType']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>融资平台标志</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictGoverFinanceSign)(state.custInfoObj['goverFinanceSign']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>融资平台类型</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictGoverFinanceType)(state.custInfoObj['goverFinanceType']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>所在国家地区</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictNationCd)(state.custInfoObj['nation']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|         </div> |  | ||||
|         <div class="pt-3"></div> |  | ||||
|         <div class="flex"> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>注册所在地</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictRegistrationCd)(state.custInfoObj['registration']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>是否集团客户</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ state.custInfoObj['groupCustInd'] === '1' ? '是' : '否' }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>成员类别</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ Formater.dictionary(dictMemberTypeCd)(state.custInfoObj['memberType']) }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>行业类型(国标)</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ state.custInfoObj['industryTypeName'] }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"> |  | ||||
|             <div>成立日期</div> |  | ||||
|             <div class="text-blue-500"> |  | ||||
|               {{ state.custInfoObj['buildDate'] }} |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div class="flex-1 text-center"></div> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|       <q-separator /> |  | ||||
|       <div class="pt-[10px]"> |  | ||||
|         <q-card flat bordered> |  | ||||
|           <q-item dense class="pl-[8px]"> |  | ||||
|             <q-item-section> |  | ||||
|               <q-item-label>灰度模型结果</q-item-label> |  | ||||
|             </q-item-section> |  | ||||
|           </q-item> |  | ||||
|           <q-separator /> |  | ||||
|           <q-card-section class="p-[10px]"> |  | ||||
|             <div class="pt-[8px]"> |  | ||||
|               <w-info-panel :dense="state.dense" :info="state.reportCustRatingInfo" :column-num="3"></w-info-panel> |  | ||||
|             </div> |  | ||||
|           </q-card-section> |  | ||||
|         </q-card> |  | ||||
|         <div class="pt-[8px]"> |  | ||||
|           <q-list bordered class="rounded-borders"> |  | ||||
|             <q-expansion-item default-opened expand-separator icon="bubble_chart" label="得分详情"> |  | ||||
|               <q-separator /> |  | ||||
|               <q-splitter v-model="state.splitterModel"> |  | ||||
|                 <template #before> |  | ||||
|                   <div> |  | ||||
|                     <div class="text-center"> |  | ||||
|                       <q-chip outline color="orange" text-color="white" :clickable="false" :ripple="false"> 定量得分详情 </q-chip> |  | ||||
|                     </div> |  | ||||
|                     <q-list v-if="state.reportQuantitativeScoreDtl" padding> |  | ||||
|                       <template v-for="(values, key, a) in state.reportQuantitativeScoreDtl" :key="a"> |  | ||||
|                         <q-item-label header>{{ key }}</q-item-label> |  | ||||
| 
 |  | ||||
|                         <template v-for="(dtl, index) in values" :key="index"> |  | ||||
|                           <q-item> |  | ||||
|                             <q-item-section> |  | ||||
|                               <q-item-label>{{ dtl['INDEX_NAME'] }}</q-item-label> |  | ||||
|                               <q-item-label caption> {{ Round(dtl['INDEX_VALUE'], 2) }} </q-item-label> |  | ||||
|                             </q-item-section> |  | ||||
|                             <q-item-section v-if="!Tools.isEmpty(dtl['INDEX_SCORE_G'])" side> |  | ||||
|                               <q-chip :clickable="false" :ripple="false" color="green" text-color="white"> {{ Round(dtl['INDEX_SCORE_G'], 2) }} </q-chip> |  | ||||
|                             </q-item-section> |  | ||||
|                           </q-item> |  | ||||
|                         </template> |  | ||||
|                         <q-separator /> |  | ||||
|                       </template> |  | ||||
|                     </q-list> |  | ||||
|                   </div> |  | ||||
|                 </template> |  | ||||
| 
 |  | ||||
|                 <template #after> |  | ||||
|                   <q-splitter v-model="state.afterSplitterModel"> |  | ||||
|                     <template #before> |  | ||||
|                       <div> |  | ||||
|                         <div class="text-center"> |  | ||||
|                           <q-chip outline color="light-blue" text-color="white" :clickable="false" :ripple="false"> 定性得分详情 </q-chip> |  | ||||
|                         </div> |  | ||||
|                         <q-list v-if="state.reportQualitativeScoreDtl" padding> |  | ||||
|                           <template v-for="(values, key, a) in state.reportQualitativeScoreDtl" :key="a"> |  | ||||
|                             <q-item-label header>{{ key }}</q-item-label> |  | ||||
| 
 |  | ||||
|                             <template v-for="(dtl, index) in values" :key="index"> |  | ||||
|                               <q-item> |  | ||||
|                                 <q-item-section> |  | ||||
|                                   <q-item-label>{{ dtl['INDEX_NAME'] }}</q-item-label> |  | ||||
|                                   <q-item-label caption> {{ dtl['TEXT'] }} </q-item-label> |  | ||||
|                                 </q-item-section> |  | ||||
|                                 <q-item-section v-if="!Tools.isEmpty(dtl['INDEX_SCORE_G'])" side> |  | ||||
|                                   <q-chip :clickable="false" :ripple="false" color="green" text-color="white"> {{ Round(dtl['INDEX_SCORE_G'], 2) }} </q-chip> |  | ||||
|                                 </q-item-section> |  | ||||
|                               </q-item> |  | ||||
|                             </template> |  | ||||
|                             <q-separator /> |  | ||||
|                           </template> |  | ||||
|                         </q-list> |  | ||||
|                       </div> |  | ||||
|                     </template> |  | ||||
| 
 |  | ||||
|                     <template #after> |  | ||||
|                       <div> |  | ||||
|                         <div class="text-center"> |  | ||||
|                           <q-chip outline color="lime" text-color="white" :clickable="false" :ripple="false"> 评级调整项详情 </q-chip> |  | ||||
|                         </div> |  | ||||
|                         <q-list v-if="state.reportAdjustScoreDtl" padding> |  | ||||
|                           <template v-for="(values, key, a) in state.reportAdjustScoreDtl" :key="a"> |  | ||||
|                             <q-item-label header>{{ key }}</q-item-label> |  | ||||
| 
 |  | ||||
|                             <template v-for="(dtl, index) in values" :key="index"> |  | ||||
|                               <q-item> |  | ||||
|                                 <q-item-section> |  | ||||
|                                   <q-item-label>{{ dtl['INDEX_NAME'] }}</q-item-label> |  | ||||
|                                   <q-item-label caption> {{ dtl['TEXT'] }} </q-item-label> |  | ||||
|                                 </q-item-section> |  | ||||
|                               </q-item> |  | ||||
|                             </template> |  | ||||
|                             <q-separator /> |  | ||||
|                           </template> |  | ||||
|                         </q-list> |  | ||||
|                       </div> |  | ||||
|                     </template> |  | ||||
|                   </q-splitter> |  | ||||
|                 </template> |  | ||||
|               </q-splitter> |  | ||||
|             </q-expansion-item> |  | ||||
|           </q-list> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|     </div> |  | ||||
|   </w-dialog> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"> |  | ||||
| import { DictionaryTools, Environment, Formater, axios, Tools } from 'platform-core'; |  | ||||
| import { nextTick, reactive, ref } from 'vue'; |  | ||||
| import { RatingStep, Round } from './CustRating.ts'; |  | ||||
| import RatingLevel from './RatingLevel.vue'; |  | ||||
| 
 |  | ||||
| const dialogRef = ref(); |  | ||||
| 
 |  | ||||
| const state = reactive({ |  | ||||
|   splitterModel: 30, |  | ||||
|   afterSplitterModel: 50, |  | ||||
|   rating: {}, |  | ||||
|   dialogTitle: '灰度模型结果', |  | ||||
|   dense: false, |  | ||||
|   custInfoObj: {}, |  | ||||
|   reportCustRatingInfo: <any>[], |  | ||||
|   reportQuantitativeScoreDtl: <any>null, |  | ||||
|   reportQualitativeScoreDtl: <any>null, |  | ||||
|   reportAdjustScoreDtl: <any>null, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| // 加载客户信息 |  | ||||
| const loadCustInfo = async () => { |  | ||||
|   // 加载客户基本信息 |  | ||||
|   let customerType = ''; |  | ||||
|   await axios.get(Environment.apiContextPath('api/irbs/ratingCompanyCustomer/' + state.rating['custId'])).then((resp) => { |  | ||||
|     if (resp && resp.data) { |  | ||||
|       customerType = resp.data['customerType']; |  | ||||
|       state.custInfoObj = {}; |  | ||||
|       state.custInfoObj['custNo'] = resp.data['custNo']; |  | ||||
|       state.custInfoObj['custName'] = resp.data['custName']; |  | ||||
|       state.custInfoObj['certificateType'] = resp.data['certificateType']; |  | ||||
|       state.custInfoObj['certificateNum'] = resp.data['certificateNum']; |  | ||||
|       state.custInfoObj['customerType'] = resp.data['customerType']; |  | ||||
|       state.custInfoObj['customerSize'] = resp.data['customerSize']; |  | ||||
|       state.custInfoObj['registeredType'] = resp.data['registeredType']; |  | ||||
|       state.custInfoObj['goverFinanceSign'] = resp.data['goverFinanceSign']; |  | ||||
|       state.custInfoObj['goverFinanceType'] = resp.data['goverFinanceType']; |  | ||||
|       state.custInfoObj['registration'] = resp.data['registration']; |  | ||||
|       state.custInfoObj['nation'] = resp.data['nation']; |  | ||||
|       state.custInfoObj['memberType'] = resp.data['memberType']; |  | ||||
|       state.custInfoObj['groupCustInd'] = resp.data['groupCustInd']; |  | ||||
|       state.custInfoObj['marketEnterprisesInd'] = resp.data['marketEnterprisesInd']; |  | ||||
|       state.custInfoObj['industryType'] = resp.data['industryType']; |  | ||||
|       state.custInfoObj['industryTypeName'] = resp.data['industryTypeName']; |  | ||||
|       state.custInfoObj['buildDate'] = resp.data['buildDate']; |  | ||||
|       state.custInfoObj['customerManagerNo'] = resp.data['customerManagerNo']; |  | ||||
|       state.custInfoObj['customerManagerName'] = resp.data['customerManagerName']; |  | ||||
|       state.custInfoObj['handleOrgId'] = resp.data['handleOrgId']; |  | ||||
|       state.custInfoObj['handleTime'] = resp.data['handleTime']; |  | ||||
|     } |  | ||||
|   }); |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const groupByProperties = (list, propName) => { |  | ||||
|   const map = {}; |  | ||||
|   list.forEach((item, index, arr) => { |  | ||||
|     if (!map[item[propName]]) { |  | ||||
|       map[item[propName]] = arr.filter((a) => a[propName] == item[propName]); |  | ||||
|     } |  | ||||
|   }); |  | ||||
|   return map; |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const loadRatingReport = async () => { |  | ||||
|   // 加载评级信息 |  | ||||
|   state.reportCustRatingInfo = []; |  | ||||
|   await axios |  | ||||
|     .get(Environment.apiContextPath('api/irbs/companyRating/stepRatingReport'), { params: { ratingId: state.rating['id'] } }) |  | ||||
|     .then((resp) => { |  | ||||
|       if (resp && resp.data) { |  | ||||
|         state.rating = resp.data; |  | ||||
|         state.reportCustRatingInfo.push({ label: '模型名称', value: resp.data.modelNameGray }); |  | ||||
|         state.reportCustRatingInfo.push({ label: '定量得分', value: Round(resp.data.quanScoreGray, 2) }); |  | ||||
|         state.reportCustRatingInfo.push({ label: '定性得分', value: Round(resp.data.qualScoreGray, 2) }); |  | ||||
|         state.reportCustRatingInfo.push({ label: '模型得分', value: Round(resp.data.modelScoreGray, 2) }); |  | ||||
|         state.reportCustRatingInfo.push({ |  | ||||
|           label: '模型级别', |  | ||||
|           value: resp.data.modelLevelGray, |  | ||||
|           format: () => { |  | ||||
|             return { |  | ||||
|               componentType: RatingLevel, |  | ||||
|               attrs: { |  | ||||
|                 level: resp.data.modelLevelGray, |  | ||||
|                 dense: true, |  | ||||
|               }, |  | ||||
|             }; |  | ||||
|           }, |  | ||||
|         }); |  | ||||
|         state.reportCustRatingInfo.push({ |  | ||||
|           label: '调整项级别', |  | ||||
|           value: resp.data.adjLevelGray, |  | ||||
|           format: () => { |  | ||||
|             return { |  | ||||
|               componentType: RatingLevel, |  | ||||
|               attrs: { |  | ||||
|                 level: resp.data.adjLevelGray, |  | ||||
|                 dense: true, |  | ||||
|               }, |  | ||||
|             }; |  | ||||
|           }, |  | ||||
|         }); |  | ||||
|       } |  | ||||
|     }) |  | ||||
|     .catch((error) => { |  | ||||
|       console.info('error====', error); |  | ||||
|     }); |  | ||||
|   // 加载得分详情 |  | ||||
|   const urlSearchParams = new URLSearchParams({ sortBy: ['INDEX_TYPE', 'INDEX_CATEGORY'] }); |  | ||||
|   urlSearchParams.append('pageable', 'false'); |  | ||||
|   const criteria = { |  | ||||
|     fieldName: 'RATING_ID', |  | ||||
|     operator: 'equals', |  | ||||
|     value: state.rating['id'], |  | ||||
|   }; |  | ||||
|   urlSearchParams.append('criteria', JSON.stringify(criteria)); |  | ||||
|   await axios |  | ||||
|     .get(Environment.apiContextPath('api/irbs/ratingIndex/getGrayScoreDetail'), { params: urlSearchParams }) |  | ||||
|     .then((resp) => { |  | ||||
|       if (resp?.data?.content) { |  | ||||
|         const groupMap = groupByProperties(resp.data.content, 'INDEX_TYPE'); |  | ||||
|         state.reportQuantitativeScoreDtl = groupByProperties(groupMap[RatingStep.DLFX], 'INDEX_CATEGORY'); |  | ||||
|         state.reportQualitativeScoreDtl = groupByProperties(groupMap[RatingStep.DXFX], 'INDEX_CATEGORY'); |  | ||||
|         state.reportAdjustScoreDtl = groupByProperties( |  | ||||
|           groupMap[RatingStep.PJTZX].filter((item) => { |  | ||||
|             return item['INDEX_VALUE'] !== '0'; |  | ||||
|           }), |  | ||||
|           'INDEX_CATEGORY', |  | ||||
|         ); |  | ||||
|       } |  | ||||
|     }) |  | ||||
|     .catch((error) => { |  | ||||
|       console.info('error====', error); |  | ||||
|     }); |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const show = async (data: any) => { |  | ||||
|   dialogRef.value.show(); |  | ||||
|   state.rating = data; |  | ||||
|   state.dialogTitle = `公司客户灰度评级结果(客户:` + data['custName'] + `)`; |  | ||||
|   loadCustInfo(); |  | ||||
|   await loadRatingReport(); |  | ||||
| }; |  | ||||
| const hide = () => { |  | ||||
|   dialogRef.value.hide(); |  | ||||
| }; |  | ||||
| 
 |  | ||||
| defineExpose({ |  | ||||
|   show, |  | ||||
|   hide, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const dictCustomerSize = await DictionaryTools.fetch('CustomerSizeCd'); |  | ||||
| const dictRegisteredType = await DictionaryTools.fetch('REGISTERED_TYPE'); |  | ||||
| const dictGoverFinanceType = await DictionaryTools.fetch('GOVER_FINANCE_TYPE'); |  | ||||
| const dictGoverFinanceSign = await DictionaryTools.fetch('GOVER_FINANCE_SIGN'); |  | ||||
| const dictRegistrationCd = await DictionaryTools.fetch('REGISTRATION_CD'); |  | ||||
| const dictNationCd = await DictionaryTools.fetch('NATION_CD'); |  | ||||
| const dictMemberTypeCd = await DictionaryTools.fetch('MEMBER_TYPE_CD'); |  | ||||
| </script> |  | ||||
| 
 |  | ||||
| <style scoped lang="css"></style> |  | ||||
| @ -1,186 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-dialog ref="dialogRef" :title="state.dialogTitle" width="80%" height="80%" :buttons="dialogButtons"> |  | ||||
|     <w-grid |  | ||||
|       ref="customerGridRef" |  | ||||
|       title="客户列表" |  | ||||
|       :fetch-data-url="Environment.apiContextPath('api/irbs/companyCustomer/query')" |  | ||||
|       :sort-no="true" |  | ||||
|       :checkbox-selection="false" |  | ||||
|       :config-button="false" |  | ||||
|       :query-form-cols-num="3" |  | ||||
|       :query-form-fields="customerGrid.queryFormFields" |  | ||||
|       :columns="customerGrid.columns" |  | ||||
|       :toolbar-actions="customerGrid.buttons" |  | ||||
|       :sort-by="['-lastModifyDate']" |  | ||||
|       :query-criteria="{ |  | ||||
|         fieldName: 'mgerNo', |  | ||||
|         operator: 'equals', |  | ||||
|         value: SessionManager.getUser().loginName, |  | ||||
|       }" |  | ||||
|     ></w-grid> |  | ||||
|   </w-dialog> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, reactive } from 'vue'; |  | ||||
| import { useQuasar } from 'quasar'; |  | ||||
| import { useI18n } from 'vue-i18n'; |  | ||||
| import { axios, noErrorAxios, Environment, NotifyManager, Formater, Tools, SessionManager } from 'platform-core'; |  | ||||
| import { SelectCustomerFlag } from './CustRating.ts'; |  | ||||
| 
 |  | ||||
| const { t } = useI18n(); |  | ||||
| const $q = useQuasar(); |  | ||||
| const dialogRef = ref(); |  | ||||
| const customerGridRef = ref(); |  | ||||
| const props = defineProps({ |  | ||||
|   dictionary: { |  | ||||
|     type: Object, |  | ||||
|     default: () => { |  | ||||
|       return {}; |  | ||||
|     }, |  | ||||
|   }, |  | ||||
| }); |  | ||||
| const emit = defineEmits(['refresh']); |  | ||||
| 
 |  | ||||
| const state = reactive({ |  | ||||
|   dialogTitle: '选择客户', |  | ||||
|   flag: SelectCustomerFlag.RATING, // 发起评级或发起违约认定标记 |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const generateRating = (rows) => { |  | ||||
|   showLoading(); |  | ||||
|   const requestParams = { |  | ||||
|     method: 'POST', |  | ||||
|     headers: { 'content-type': 'application/json;charset=utf-8;' }, |  | ||||
|     url: Environment.apiContextPath('api/irbs/companyRating/generateRating/' + rows[0]['custNo']), |  | ||||
|   }; |  | ||||
|   noErrorAxios(requestParams) |  | ||||
|     .then((resp) => { |  | ||||
|       hideLoading(); |  | ||||
|       emit('refresh'); |  | ||||
|       dialogRef.value.hide(); |  | ||||
|       NotifyManager.info('发起成功'); |  | ||||
|     }) |  | ||||
|     .catch((error) => { |  | ||||
|       const response = error?.response; |  | ||||
|       const status = response?.status; |  | ||||
|       const data = response?.data; |  | ||||
|       //其他错误 |  | ||||
|       if (status === 500 && data.exception === 'java.lang.RuntimeException' && !Tools.isEmpty(data.errorMessage)) { |  | ||||
|         NotifyManager.error(data.errorMessage); |  | ||||
|       } else if (status === 500) { |  | ||||
|         NotifyManager.error(t(data?.errorMessageI18nKey)); |  | ||||
|       } else { |  | ||||
|         NotifyManager.error(t(status)); |  | ||||
|       } |  | ||||
|     }); |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const dialogButtons = [ |  | ||||
|   { |  | ||||
|     label: '确定', |  | ||||
|     icon: 'beenhere', |  | ||||
|     click: async () => { |  | ||||
|       const rows = customerGridRef.value.getSelectedRows(); |  | ||||
|       if (rows.length === 0) { |  | ||||
|         NotifyManager.warn('请选择客户'); |  | ||||
|         return; |  | ||||
|       } |  | ||||
|       if (state.flag === SelectCustomerFlag.RATING) { |  | ||||
|         // 判断客户是否已达当月评级次数上限 |  | ||||
|         const monthLimit = await axios.post(Environment.apiContextPath('api/irbs/companyRating/getMonthRatingLimit/' + rows[0]['custNo'])); |  | ||||
|         console.info('monthLimit====', monthLimit); |  | ||||
|         if (monthLimit?.data?.result === true && monthLimit?.data?.tactics === '1') { |  | ||||
|           NotifyManager.warn('该客户当月已达评级次数上限(' + monthLimit?.data?.num + '次),无法再次发起评级'); |  | ||||
|           return; |  | ||||
|         } else if (monthLimit?.data?.result === true && monthLimit?.data?.tactics === '2') { |  | ||||
|           $q.dialog({ |  | ||||
|             title: '询问', |  | ||||
|             message: '该客户当月已发起评级次数超过:' + monthLimit?.data?.num + '次,是否继续发起?', |  | ||||
|             cancel: { noCaps: true }, |  | ||||
|             ok: { noCaps: true }, |  | ||||
|             persistent: true, |  | ||||
|           }).onOk(() => { |  | ||||
|             generateRating(rows); |  | ||||
|           }); |  | ||||
|         } else { |  | ||||
|           generateRating(rows); |  | ||||
|         } |  | ||||
|       } else if (state.flag === SelectCustomerFlag.COGNIZANCE) { |  | ||||
|         // 查询是否有在途流程 |  | ||||
|         const resp = await axios |  | ||||
|           .get(Environment.apiContextPath('api/irbs/defaultCognizance/queryDefaCustNo'), { params: { custNo: rows[0]['custNo'] } }) |  | ||||
|           .catch((error) => { |  | ||||
|             console.info('error-------------', error); |  | ||||
|           }); |  | ||||
|         if (resp && resp.data === '1') { |  | ||||
|           NotifyManager.warn('当前客户存在进行中违约认定流程'); |  | ||||
|           return; |  | ||||
|         } else if (resp && resp.data === '2') { |  | ||||
|           NotifyManager.warn('当前客户存在已人工认定违约认定结果,无法发起新的人工违约认定流程'); |  | ||||
|           return; |  | ||||
|         } else if (resp && resp.data === '0') { |  | ||||
|           // 发起 |  | ||||
|           showLoading(); |  | ||||
|           axios |  | ||||
|             .post(Environment.apiContextPath('api/irbs/defaultManager/cognizanceApply'), { custNo: rows[0]['custNo'], type: 'F' }) |  | ||||
|             .then((resp) => { |  | ||||
|               hideLoading(); |  | ||||
|               if (resp && resp['code'] === 200 && resp['data']) { |  | ||||
|                 emit('refresh'); |  | ||||
|                 dialogRef.value.hide(); |  | ||||
|               } |  | ||||
|             }) |  | ||||
|             .catch((error) => { |  | ||||
|               hideLoading(); |  | ||||
|               console.info('error-------------', error); |  | ||||
|             }); |  | ||||
|         } |  | ||||
|       } |  | ||||
|     }, |  | ||||
|   }, |  | ||||
| ]; |  | ||||
| 
 |  | ||||
| const customerGrid = { |  | ||||
|   queryFormFields: [ |  | ||||
|     { label: '客户号', name: 'custNo', type: 'w-text' }, //defaultValue: '2100601306' |  | ||||
|     { label: '客户名称', name: 'custName', type: 'w-text' }, |  | ||||
|     { label: '企业规模', name: 'corpSizeCd', type: 'w-select', options: props.dictionary.optionsCustomerSizeCd }, |  | ||||
|   ], |  | ||||
|   buttons: ['query', 'reset'], |  | ||||
|   columns: [ |  | ||||
|     { name: 'custNo', label: '客户号' }, |  | ||||
|     { name: 'custName', label: '客户名称' }, |  | ||||
|     { name: 'induSortName', label: '行业类型' }, |  | ||||
|     { name: 'custTypeCd', label: '客户类型', format: Formater.dictionary(props.dictionary.dictCustomerTypeCd) }, |  | ||||
|     { name: 'buildDt', label: '成立时间' }, |  | ||||
|     { name: 'corpSizeCd', label: '企业规模', format: Formater.dictionary(props.dictionary.dictCustomerSizeCd) }, |  | ||||
|   ], |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const show = (flag) => { |  | ||||
|   if (flag) { |  | ||||
|     state.flag = flag; |  | ||||
|   } |  | ||||
|   dialogRef.value.show(); |  | ||||
| }; |  | ||||
| const hide = () => { |  | ||||
|   dialogRef.value.hide(); |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const showLoading = (msg: string = '正在处理,请稍等...') => { |  | ||||
|   $q.loading.show({ |  | ||||
|     message: msg, |  | ||||
|     boxClass: 'bg-grey-2 text-grey-9', |  | ||||
|     spinnerColor: 'primary', |  | ||||
|   }); |  | ||||
| }; |  | ||||
| const hideLoading = () => { |  | ||||
|   $q.loading.hide(); |  | ||||
| }; |  | ||||
| 
 |  | ||||
| defineExpose({ |  | ||||
|   show, |  | ||||
|   hide, |  | ||||
| }); |  | ||||
| </script> |  | ||||
								
									
										File diff suppressed because it is too large
									
								
							
						
					| @ -1,31 +0,0 @@ | |||||
| <template> |  | ||||
|   <div> |  | ||||
|     <q-knob v-model="value" :min="1" :max="10" readonly show-value :size="size" :color="color" track-color="grey-3" v-bind="attrs"> |  | ||||
|       <span>{{ props.level }}</span> |  | ||||
|     </q-knob> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, useAttrs } from 'vue'; |  | ||||
| import { RatingLevelOptions } from './CustRating.ts'; |  | ||||
| 
 |  | ||||
| const attrs = useAttrs(); |  | ||||
| const props = defineProps({ |  | ||||
|   level: { type: String, default: '' }, |  | ||||
|   size: { type: String, default: 'md' }, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const value = ref(0); |  | ||||
| const color = ref('teal'); |  | ||||
| 
 |  | ||||
| const ratingLevel = RatingLevelOptions.find((item) => { |  | ||||
|   return item['value'] === props.level; |  | ||||
| }); |  | ||||
| if (ratingLevel) { |  | ||||
|   value.value = ratingLevel.numberValue; |  | ||||
|   color.value = ratingLevel.color; |  | ||||
| } |  | ||||
| </script> |  | ||||
| 
 |  | ||||
| <style scoped lang="css"></style> |  | ||||
| @ -1,61 +0,0 @@ | |||||
| <template> |  | ||||
|   <q-slider |  | ||||
|     v-model="ratingLevel" |  | ||||
|     dense |  | ||||
|     readonly |  | ||||
|     color="blue" |  | ||||
|     :label-always="labelAlwaysComputed" |  | ||||
|     :label-value="labelValueComputed" |  | ||||
|     :marker-labels="labelsComputed" |  | ||||
|     :min="minLevel" |  | ||||
|     :max="maxLevel" |  | ||||
|     style="width: 95%" |  | ||||
|   /> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, computed } from 'vue'; |  | ||||
| import { RatingLevelOptions } from './CustRating'; |  | ||||
| 
 |  | ||||
| const modelValue = defineModel<string>(); |  | ||||
| const minLevel = ref(RatingLevelOptions.find((item) => item.value === 'D')?.numberValue); |  | ||||
| const maxLevel = ref(RatingLevelOptions.find((item) => item.value === 'AAA+')?.numberValue); |  | ||||
| 
 |  | ||||
| const props = defineProps({ |  | ||||
|   // marker-labels 精简模式 |  | ||||
|   denseLabel: { type: Boolean, default: false }, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const ratingLevel = computed(() => { |  | ||||
|   const ratingLevel_ = RatingLevelOptions.find((item) => { |  | ||||
|     return item['value'] === modelValue.value; |  | ||||
|   }); |  | ||||
|   if (ratingLevel_) { |  | ||||
|     return ratingLevel_.numberValue; |  | ||||
|   } |  | ||||
|   return 1; |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const labelsComputed = computed(() => { |  | ||||
|   const result = <any>[]; |  | ||||
|   RatingLevelOptions.forEach((item) => { |  | ||||
|     if (props.denseLabel && item.denseLabel) { |  | ||||
|       result.push({ |  | ||||
|         label: item.label, |  | ||||
|         value: item.numberValue, |  | ||||
|       }); |  | ||||
|     } else if (!props.denseLabel) { |  | ||||
|       result.push({ |  | ||||
|         label: item.label, |  | ||||
|         value: item.numberValue, |  | ||||
|       }); |  | ||||
|     } |  | ||||
|   }); |  | ||||
|   return result; |  | ||||
| }); |  | ||||
| const labelAlwaysComputed = computed(() => { |  | ||||
|   return props.denseLabel; |  | ||||
| }); |  | ||||
| const labelValueComputed = computed(() => { |  | ||||
|   return modelValue.value; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,69 +0,0 @@ | |||||
| <template> |  | ||||
|   <div> |  | ||||
|     <q-btn |  | ||||
|       v-if="showComputed" |  | ||||
|       icon="mark_chat_unread" |  | ||||
|       color="primary" |  | ||||
|       label="批注" |  | ||||
|       @click=" |  | ||||
|         () => { |  | ||||
|           addAnnotationRef.show(); |  | ||||
|         } |  | ||||
|       " |  | ||||
|     /> |  | ||||
|     <w-drawer ref="addAnnotationRef" title="批注"> |  | ||||
|       <div class="p-2 h-full"> |  | ||||
|         <w-splitter :size="205" horizontal unit="px" disable :show-separator="false"> |  | ||||
|           <template #before> |  | ||||
|             <w-form ref="formRef" :cols-num="1" :fields="[{ label: '批注内容', name: 'annotation', type: 'w-textarea' }]"></w-form> |  | ||||
|             <br /> |  | ||||
|             <q-btn |  | ||||
|               icon="add" |  | ||||
|               color="primary" |  | ||||
|               label="添加" |  | ||||
|               @click=" |  | ||||
|                 () => { |  | ||||
|                   annotationGridRef.addLocalData({ nr: formRef.getData()['annotation'], sj: currDate() }); |  | ||||
|                 } |  | ||||
|               " |  | ||||
|             /> |  | ||||
|           </template> |  | ||||
|           <template #after> |  | ||||
|             <div class="h-full"> |  | ||||
|               <w-grid |  | ||||
|                 ref="annotationGridRef" |  | ||||
|                 :auto-fetch-data="false" |  | ||||
|                 :config-button="false" |  | ||||
|                 :toolbar-actions="['refresh', 'remove']" |  | ||||
|                 :columns="[ |  | ||||
|                   { label: '批注内容', name: 'nr' }, |  | ||||
|                   { label: '批注时间', name: 'sj', width: 200 }, |  | ||||
|                 ]" |  | ||||
|               > |  | ||||
|               </w-grid> |  | ||||
|             </div> |  | ||||
|           </template> |  | ||||
|         </w-splitter> |  | ||||
|       </div> |  | ||||
|     </w-drawer> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, inject, computed } from 'vue'; |  | ||||
| import { Rating } from './ts/Rating'; |  | ||||
| import { Step } from './ts/Step'; |  | ||||
| import { Constant } from './ts/Constant'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const addAnnotationRef = ref(); |  | ||||
| const annotationGridRef = ref(); |  | ||||
| const formRef = ref(); |  | ||||
| const currDate = () => { |  | ||||
|   const now = new Date(); |  | ||||
|   const formattedTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`; |  | ||||
|   return formattedTime; |  | ||||
| }; |  | ||||
| const showComputed = computed(() => { |  | ||||
|   return true; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,37 +0,0 @@ | |||||
| <template> |  | ||||
|   <CustInfo v-if="custComputed"></CustInfo> |  | ||||
|   <QuanQualAnalysis v-else-if="qqaComputed"></QuanQualAnalysis> |  | ||||
|   <AdjustItem v-else-if="aiComputed"></AdjustItem> |  | ||||
|   <ReportInfo v-else-if="riComputed"></ReportInfo> |  | ||||
|   <Opinion v-else-if="opinionComputed"></Opinion> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, PropType, computed } from 'vue'; |  | ||||
| import type { StepType } from './ts/type/StepType'; |  | ||||
| import { Step } from './ts/Step'; |  | ||||
| import CustInfo from './content/CustInfo.vue'; |  | ||||
| import QuanQualAnalysis from './content/QuanQualAnalysis.vue'; |  | ||||
| import AdjustItem from './content/AdjustItem.vue'; |  | ||||
| import ReportInfo from './content/ReportInfo.vue'; |  | ||||
| import Opinion from './content/Opinion.vue'; |  | ||||
| 
 |  | ||||
| const props = defineProps({ |  | ||||
|   step: { type: Object as PropType<StepType>, default: undefined }, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const custComputed = computed(() => { |  | ||||
|   return props.step?.value === Step.type.custInfo.value; |  | ||||
| }); |  | ||||
| const qqaComputed = computed(() => { |  | ||||
|   return props.step?.value === Step.type.quanQualAnalysis.value; |  | ||||
| }); |  | ||||
| const aiComputed = computed(() => { |  | ||||
|   return props.step?.value === Step.type.adjustItem.value; |  | ||||
| }); |  | ||||
| const riComputed = computed(() => { |  | ||||
|   return props.step?.value === Step.type.reportInfo.value; |  | ||||
| }); |  | ||||
| const opinionComputed = computed(() => { |  | ||||
|   return props.step?.value === Step.type.opinion.value; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,21 +0,0 @@ | |||||
| <template> |  | ||||
|   <q-btn v-if="showComputed" icon="next_plan" color="primary" label="下一步" @click="rating.step.nextClick" /> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, computed } from 'vue'; |  | ||||
| import { Rating } from './ts/Rating'; |  | ||||
| import { Step } from './ts/Step'; |  | ||||
| import { Constant } from './ts/Constant'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const showComputed = computed(() => { |  | ||||
|   if (rating.ratingData.value['processStatus'] === Constant.RATING_PROCESS_STATUS.BACK && rating.step.currStep.value === Step.type.reportInfo.value) { |  | ||||
|     return false; |  | ||||
|   } else { |  | ||||
|     if (rating.cm.isApplyUserProcessStatus.value && rating.step.currStep.value !== Step.type.opinion.value) { |  | ||||
|       return true; |  | ||||
|     } |  | ||||
|   } |  | ||||
|   return false; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,71 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="46" horizontal disable reverse unit="px" style="height: 100%"> |  | ||||
|     <template #before> |  | ||||
|       <Step ref="stepRef" class="h-full"></Step> |  | ||||
|     </template> |  | ||||
| 
 |  | ||||
|     <template #after> |  | ||||
|       <div class="p-1 flex justify-end gap-x-4"> |  | ||||
|         <AnnotationButton></AnnotationButton> |  | ||||
|         <!-- <TestCalcButton></TestCalcButton> --> |  | ||||
|         <NextButton></NextButton> |  | ||||
|         <WorkflowButton></WorkflowButton> |  | ||||
|       </div> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { VueTools } from 'platform-core'; |  | ||||
| import { getCurrentInstance, onMounted, provide, ref, shallowRef } from 'vue'; |  | ||||
| import RatingLevel from '../RatingLevel.vue'; |  | ||||
| import NextButton from './NextButton.vue'; |  | ||||
| import Step from './Step.vue'; |  | ||||
| import TestCalcButton from './TestCalcButton.vue'; |  | ||||
| import { Rating } from './ts/Rating'; |  | ||||
| import WorkflowButton from './WorkflowButton.vue'; |  | ||||
| import AnnotationButton from './AnnotationButton.vue'; |  | ||||
| 
 |  | ||||
| const RatingLevelRef = shallowRef(RatingLevel); |  | ||||
| const props = defineProps({ |  | ||||
|   ratingData: { |  | ||||
|     type: Object, |  | ||||
|     default: () => { |  | ||||
|       return {}; |  | ||||
|     }, |  | ||||
|   }, |  | ||||
|   readMode: { |  | ||||
|     type: Boolean, |  | ||||
|     default: false, |  | ||||
|   }, |  | ||||
| }); |  | ||||
| const emit = defineEmits(['afterComplete']); |  | ||||
| 
 |  | ||||
| const rating = new Rating(props.ratingData, props.readMode); |  | ||||
| await rating.dictionary.load(); |  | ||||
| await rating.enum.load(); |  | ||||
| await rating.systemParameter.load(); |  | ||||
| const ratingLevelFormat = (modelLevel: any, size: string) => { |  | ||||
|   return { |  | ||||
|     componentType: RatingLevelRef, |  | ||||
|     attrs: { |  | ||||
|       level: modelLevel, |  | ||||
|       dense: true, |  | ||||
|       size: size, |  | ||||
|     }, |  | ||||
|   }; |  | ||||
| }; |  | ||||
| rating.refs.setRatingLevelFormatFunction(ratingLevelFormat); |  | ||||
| 
 |  | ||||
| onMounted(() => { |  | ||||
|   rating.step.setCurrStep(rating.ratingData.value['currentStep']); |  | ||||
| }); |  | ||||
| 
 |  | ||||
| // 获得自身实例 |  | ||||
| const instance = getCurrentInstance(); |  | ||||
| // 将对外暴露API添加至自身实例中 |  | ||||
| VueTools.expose2Instance(instance); |  | ||||
| // 设置到评级类中 |  | ||||
| rating.setInstance(instance); |  | ||||
| 
 |  | ||||
| provide('rating', rating); |  | ||||
| </script> |  | ||||
| @ -1,58 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="75" class="h-full" unit="px" disable> |  | ||||
|     <template #before> |  | ||||
|       <div class="h-full" style="display: flex; align-items: center"> |  | ||||
|         <q-tabs |  | ||||
|           v-model="rating.step.currStep.value" |  | ||||
|           vertical |  | ||||
|           indicator-color="amber" |  | ||||
|           active-color="amber" |  | ||||
|           align="left" |  | ||||
|           :dense="rating.cm.isAwaitSubmitProcessStatus.value" |  | ||||
|           style="height: auto" |  | ||||
|           @update:model-value="rating.step.click" |  | ||||
|         > |  | ||||
|           <template v-for="(step, index) in rating.step.steps.value" :key="step.value"> |  | ||||
|             <q-tab :name="step.value" :icon="step.icon" :label="step.label" :disable="step.disable" style="padding: 2px"> |  | ||||
|               <q-tooltip v-if="rating.cm.isAwaitSubmitProcessStatus.value" transition-show="rotate" transition-hide="rotate">{{ step.tooltip }}</q-tooltip> |  | ||||
|             </q-tab> |  | ||||
|             <div v-if="index !== rating.step.steps.value.length - 1 && rating.cm.isAwaitSubmitProcessStatus.value" style="width: 100%; text-align: center"> |  | ||||
|               <q-icon name="bi-arrow-down-short" size="sm"></q-icon> |  | ||||
|             </div> |  | ||||
|           </template> |  | ||||
|         </q-tabs> |  | ||||
|       </div> |  | ||||
|     </template> |  | ||||
|     <template #after> |  | ||||
|       <!-- 切分窗口 --> |  | ||||
|       <w-splitter v-if="!rating.cm.isAwaitSubmitProcessStatus.value" :size="77" :separator-color="rating.separatorColor" class="h-full"> |  | ||||
|         <template #before> |  | ||||
|           <q-tab-panels v-model="rating.step.currStep.value" class="p-0 h-full"> |  | ||||
|             <q-tab-panel v-for="step in rating.step.steps.value" :key="step.value" :name="step.value" class="p-0 h-full"> |  | ||||
|               <Content :step="step"></Content> |  | ||||
|             </q-tab-panel> |  | ||||
|           </q-tab-panels> |  | ||||
|         </template> |  | ||||
|         <template #after> |  | ||||
|           <Opinion></Opinion> |  | ||||
|         </template> |  | ||||
|       </w-splitter> |  | ||||
|       <!-- 不切分 --> |  | ||||
|       <q-tab-panels v-else v-model="rating.step.currStep.value" class="p-0 h-full"> |  | ||||
|         <q-tab-panel v-for="step in rating.step.steps.value" :key="step.value" :name="step.value" class="p-0 h-full"> |  | ||||
|           <Content :step="step"></Content> |  | ||||
|         </q-tab-panel> |  | ||||
|       </q-tab-panels> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| 
 |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, ref, onMounted } from 'vue'; |  | ||||
| import { Rating } from './ts/Rating'; |  | ||||
| import Content from './Content.vue'; |  | ||||
| import { Constant } from './ts/Constant'; |  | ||||
| import Opinion from './content/Opinion.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,73 +0,0 @@ | |||||
| <template> |  | ||||
|   <q-btn v-if="showComputed" icon="calculate" color="primary" label="试算" :disable="testCalcNum < 1" @click="click"> |  | ||||
|     <q-badge :color="testCalcNum > 3 ? 'green' : 'red'" floating |  | ||||
|       >{{ testCalcNum }} |  | ||||
|       <q-tooltip> 剩余可试算次数 </q-tooltip> |  | ||||
|     </q-badge> |  | ||||
|   </q-btn> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, inject, computed, onBeforeMount } from 'vue'; |  | ||||
| import { useQuasar } from 'quasar'; |  | ||||
| import { axios, Environment, NotifyManager, Tools } from 'platform-core'; |  | ||||
| import { Rating } from './ts/Rating'; |  | ||||
| import { Step } from './ts/Step'; |  | ||||
| import { Constant } from './ts/Constant'; |  | ||||
| import { round } from './ts/Utils'; |  | ||||
| 
 |  | ||||
| const $q = useQuasar(); |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const testCalcNum = ref(0); |  | ||||
| 
 |  | ||||
| const getTestCalcNum = async () => { |  | ||||
|   const resp = await axios.get(Environment.apiContextPath('api/irbs/companyRating/getQualTestCalcNum'), { |  | ||||
|     params: { ratingId: rating.ratingData.value['id'] }, |  | ||||
|   }); |  | ||||
|   if (resp?.data) { |  | ||||
|     testCalcNum.value = resp.data; |  | ||||
|   } |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const click = async () => { |  | ||||
|   const result = rating.step.qualFormValidate(); |  | ||||
|   if (!result['result']) { |  | ||||
|     return; |  | ||||
|   } |  | ||||
|   rating.showLoading('正在计算定性得分,请稍等...'); |  | ||||
|   const url = Environment.apiContextPath('api/irbs/companyRating/qualSaveIndices/' + Constant.QUAL_SAVE_OPERATOR.TEST); |  | ||||
|   const resp = await axios.post(url, result['submitData']).catch((error) => { |  | ||||
|     rating.hideLoading(); |  | ||||
|     NotifyManager.error('计算出错,请联系管理员'); |  | ||||
|     console.info('error====', error); |  | ||||
|   }); |  | ||||
|   rating.hideLoading(); |  | ||||
|   if (resp?.data?.success === true) { |  | ||||
|     rating.ratingData.value['lastQualTestCalcScore'] = round(resp.data.qualScore, 2); |  | ||||
|     $q.dialog({ |  | ||||
|       title: '消息', |  | ||||
|       message: '本次试算定性得分为:' + round(resp.data.qualScore, 2), |  | ||||
|       cancel: false, |  | ||||
|       persistent: true, |  | ||||
|     }); |  | ||||
|     // 获取最新试算次数 |  | ||||
|     getTestCalcNum(); |  | ||||
|   } else if (resp?.data?.success === false && !Tools.isEmpty(resp.data.errorMsg)) { |  | ||||
|     if (rating.ratingData.value['lastQualTestCalcScore']) { |  | ||||
|       NotifyManager.error(resp.data.errorMsg + ',与最后一次试算结果相同,得分为:' + rating.ratingData.value['lastQualTestCalcScore']); |  | ||||
|     } else { |  | ||||
|       NotifyManager.error(resp.data.errorMsg); |  | ||||
|     } |  | ||||
|   } |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const showComputed = computed(() => { |  | ||||
|   if (rating.cm.isApplyUserProcessStatus.value && rating.step.currStep.value === Step.type.quanQualAnalysis.value) { |  | ||||
|     return true; |  | ||||
|   } |  | ||||
|   return false; |  | ||||
| }); |  | ||||
| 
 |  | ||||
| onBeforeMount(() => { |  | ||||
|   getTestCalcNum(); |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,48 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-workflow-action |  | ||||
|     v-if="showComputed" |  | ||||
|     :task-id="rating.ratingData.value['taskId']" |  | ||||
|     :data="rating.opinionData.value" |  | ||||
|     :default-submit-button="false" |  | ||||
|     :action-url="Environment.apiContextPath('/api/irbs/companyRatingProcess/submit')" |  | ||||
|     @before-submit=" |  | ||||
|       async (action, callback) => { |  | ||||
|         rating.opinionData.value = { |  | ||||
|           transientVariables: { |  | ||||
|             opaVal: action.transientVariables.goback, |  | ||||
|             desc: '客户名称:' + rating.ratingData.value['custName'], |  | ||||
|           }, |  | ||||
|           data: rating.refs.overturnFormRefFunction().getData(), |  | ||||
|         }; |  | ||||
|         const validateResult = await rating.refs.overturnFormRefFunction().validate(); |  | ||||
|         if (validateResult) { |  | ||||
|           callback(true); |  | ||||
|         } else { |  | ||||
|           callback(false); |  | ||||
|         } |  | ||||
|       } |  | ||||
|     " |  | ||||
|     @after-submit=" |  | ||||
|       () => { |  | ||||
|         rating.instance.emit('afterComplete'); |  | ||||
|       } |  | ||||
|     " |  | ||||
|   > |  | ||||
|   </w-workflow-action> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, computed } from 'vue'; |  | ||||
| import { Environment } from 'platform-core'; |  | ||||
| import { Rating } from './ts/Rating'; |  | ||||
| import { Step } from './ts/Step'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const showComputed = computed(() => { |  | ||||
|   if (rating.cm.isAwaitSubmitProcessStatus.value) { |  | ||||
|     return rating.step.currStep.value === Step.type.opinion.value; |  | ||||
|   } else if (rating.ratingData.value['taskId']) { |  | ||||
|     return true; |  | ||||
|   } |  | ||||
|   return false; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,18 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="45" unit="px" horizontal disable> |  | ||||
|     <template #before> |  | ||||
|       <FirstRatingResult></FirstRatingResult> |  | ||||
|     </template> |  | ||||
|     <template #after> |  | ||||
|       <AdjustItemGrid class="px-1"></AdjustItemGrid> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, computed } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import FirstRatingResult from './FirstRatingResult.vue'; |  | ||||
| import AdjustItemGrid from './AdjustItemGrid.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,68 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     ref="adjustItemGridRef" |  | ||||
|     title="评级调整项列表" |  | ||||
|     :dense="rating.dense" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="false" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     group-mode="alone" |  | ||||
|     group-by-field="indexCategory" |  | ||||
|     :stripe="true" |  | ||||
|     :sort-no="false" |  | ||||
|     :config-button="false" |  | ||||
|     :toolbar-actions="['expand']" |  | ||||
|     :columns="[ |  | ||||
|       { |  | ||||
|         name: 'value', |  | ||||
|         label: '符合', |  | ||||
|         width: 80, |  | ||||
|         align: 'center', |  | ||||
|         sortable: false, |  | ||||
|         format: (val) => { |  | ||||
|           return { |  | ||||
|             componentType: 'w-checkbox', |  | ||||
|             bindModelValue: true, |  | ||||
|             attrs: { |  | ||||
|               dense: true, |  | ||||
|               disableIf: () => { |  | ||||
|                 // if (showNextBtnComputed) { |  | ||||
|                 //   return false; |  | ||||
|                 // } |  | ||||
|                 return false; |  | ||||
|               }, |  | ||||
|             }, |  | ||||
|           }; |  | ||||
|         }, |  | ||||
|       }, |  | ||||
|       { |  | ||||
|         name: 'indexCategory', |  | ||||
|         label: '调整项分类', |  | ||||
|         showIf: false, |  | ||||
|       }, |  | ||||
|       { |  | ||||
|         name: 'indexCode', |  | ||||
|         label: '调整项编码', |  | ||||
|         sortable: false, |  | ||||
|       }, |  | ||||
|       { |  | ||||
|         name: 'adjustItemName', |  | ||||
|         label: '调整项(<span class=\'text-red-500\'>若客户符合调整项所描述情况,请在【符合】列打勾</span>)', |  | ||||
|         sortable: false, |  | ||||
|       }, |  | ||||
|     ]" |  | ||||
|     @row-db-click="() => {}" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, ref } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const adjustItemGridRef = ref(); |  | ||||
| const getAdjustItemGridRef = () => { |  | ||||
|   return adjustItemGridRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setAdjustItemGridRefFunction(getAdjustItemGridRef); |  | ||||
| </script> |  | ||||
| @ -1,36 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="34" horizontal unit="px" disable class="h-full"> |  | ||||
|     <template #before> |  | ||||
|       <w-card-panel |  | ||||
|         label="评级调整项详情" |  | ||||
|         :bordered="false" |  | ||||
|         :title-mode="true" |  | ||||
|         icon="build_circle" |  | ||||
|         :icon-attrs="{ color: 'yellow' }" |  | ||||
|         color="yellow" |  | ||||
|       ></w-card-panel> |  | ||||
|     </template> |  | ||||
|     <template #after> |  | ||||
|       <q-list v-if="rating.adjustItemScoreDtlData.value" padding> |  | ||||
|         <template v-for="(values, key, a) in rating.adjustItemScoreDtlData.value" :key="a"> |  | ||||
|           <q-item-label header>{{ key }}</q-item-label> |  | ||||
| 
 |  | ||||
|           <template v-for="(dtl, index) in values" :key="index"> |  | ||||
|             <q-item> |  | ||||
|               <q-item-section> |  | ||||
|                 <q-item-label>{{ index + 1 }}、{{ dtl['INDEX_NAME'] }}</q-item-label> |  | ||||
|                 <!-- <q-item-label caption> {{ dtl['TEXT'] }} </q-item-label> --> |  | ||||
|               </q-item-section> |  | ||||
|             </q-item> |  | ||||
|           </template> |  | ||||
|           <!-- <q-separator /> --> |  | ||||
|         </template> |  | ||||
|       </q-list> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,38 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     ref="creditReportGridRef" |  | ||||
|     title="征信报告" |  | ||||
|     :dense="rating.dense" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="false" |  | ||||
|     :fetch-data-url="Environment.apiContextPath('api/irbs/creditReport')" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     :config-button="false" |  | ||||
|     :columns="[ |  | ||||
|       { name: 'id', label: '报告号' }, |  | ||||
|       { name: 'custNo', label: '客户号' }, |  | ||||
|       { name: 'entName', label: '客户名称' }, |  | ||||
|       { name: 'reportDate', label: '报告日期', format: Formater.dateOnly() }, |  | ||||
|       { name: 'expiryDate', label: '征信有效期', format: Formater.dateOnly() }, |  | ||||
|       { name: 'blankInd', label: '是否白户', slot: 'isValid' }, |  | ||||
|     ]" |  | ||||
|     :query-criteria="{ |  | ||||
|       fieldName: 'custNo', |  | ||||
|       operator: 'equals', |  | ||||
|       value: '', |  | ||||
|     }" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, inject } from 'vue'; |  | ||||
| import { Formater, Environment } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const creditReportGridRef = ref(); |  | ||||
| const getCreditReportGridRef = () => { |  | ||||
|   return creditReportGridRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setCreditReportGridRefFunction(getCreditReportGridRef); |  | ||||
| </script> |  | ||||
| @ -1,29 +0,0 @@ | |||||
| <template> |  | ||||
|   <q-card flat bordered> |  | ||||
|     <q-card-section> |  | ||||
|       <span class="text-3xl"> |  | ||||
|         {{ rating.custInfoData.value['custName'] }} |  | ||||
|         <!-- <q-badge v-if="rating.custInfoData.value['marketEnterprisesInd'] === '1'" color="red" align="top">上市</q-badge> --> |  | ||||
|         <q-badge color="orange" align="top">客户号:{{ rating.custInfoData.value['custNo'] }}</q-badge |  | ||||
|         >  <q-badge color="green" align="top">上市</q-badge>  |  | ||||
|         <q-badge color="red" align="top">{{ Formater.dictionary(rating.dictionary.customerSize)(rating.custInfoData.value['customerSize']) }}</q-badge |  | ||||
|         >  <q-badge align="top">{{ Formater.dictionary(rating.dictionary.registeredType)(rating.custInfoData.value['registeredType']) }}</q-badge |  | ||||
|         >  <q-badge color="secondary" align="top">{{ rating.custInfoData.value['groupCustInd'] === '1' ? '集团客户' : '非集团客户' }}</q-badge |  | ||||
|         >  |  | ||||
|         <q-badge v-if="rating.custInfoData.value['groupCustInd'] === '1'" align="top" |  | ||||
|           >集团成员类别:{{ Formater.dictionary(rating.dictionary.memberTypeCd)(rating.custInfoData.value['memberType']) }}</q-badge |  | ||||
|         ><template v-if="rating.custInfoData.value['groupCustInd'] === '1'"> </template> |  | ||||
|         <q-badge color="blue" align="top">行业:{{ rating.custInfoData.value['industryTypeName'] }}</q-badge |  | ||||
|         >  <q-badge color="brown" align="top">成立日期:{{ rating.custInfoData.value['buildDate'] }}</q-badge |  | ||||
|         >  |  | ||||
|       </span> |  | ||||
|     </q-card-section> |  | ||||
|   </q-card> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { Formater } from 'platform-core'; |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,61 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="48" unit="px" horizontal disable> |  | ||||
|     <template #before> |  | ||||
|       <div class="py-1 pl-1 flex flex-nowrap items-start gap-x-2"> |  | ||||
|         <div class="flex-1"> |  | ||||
|           <w-form |  | ||||
|             :cols-num="3" |  | ||||
|             :fields="[ |  | ||||
|               { |  | ||||
|                 label: '评分卡', |  | ||||
|                 name: 'modelName', |  | ||||
|                 type: 'w-select', |  | ||||
|                 options: ['A评分卡', 'B评分卡', 'K评分卡'], |  | ||||
|                 defaultValue: rating.ratingData.value['modelName'], |  | ||||
|               }, |  | ||||
|               { |  | ||||
|                 label: '更改评分卡说明', |  | ||||
|                 name: 'updateModelDesc', |  | ||||
|                 type: 'w-text', |  | ||||
|                 colSpan: 2, |  | ||||
|               }, |  | ||||
|             ]" |  | ||||
|           > |  | ||||
|           </w-form> |  | ||||
|         </div> |  | ||||
|         <div class="flex-none pr-4"> |  | ||||
|           <q-btn icon="task_alt" color="primary" label="更改" @click="click" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|     </template> |  | ||||
|     <template #after> |  | ||||
|       <w-splitter :size="70" :limits="[30, 95]" horizontal :separator-color="rating.separatorColor"> |  | ||||
|         <template #before> |  | ||||
|           <FinanceReportTabs></FinanceReportTabs> |  | ||||
|         </template> |  | ||||
|         <template #after> |  | ||||
|           <CreditReportGrid class="px-1"></CreditReportGrid> |  | ||||
|         </template> |  | ||||
|       </w-splitter> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, inject } from 'vue'; |  | ||||
| import { DialogManager } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import FinanceReportGrid from './FinanceReportGrid.vue'; |  | ||||
| import CreditReportGrid from './CreditReportGrid.vue'; |  | ||||
| import CustBaseInfo from './CustBaseInfo.vue'; |  | ||||
| import FinanceReportTabs from './FinanceReportTabs.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const custFormRef = ref(); |  | ||||
| const getCustFormRef = () => { |  | ||||
|   return custFormRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setCustFormRefFunction(getCustFormRef); |  | ||||
| const click = () => { |  | ||||
|   DialogManager.confirm('更改评分卡后流程会经总行进行审批,确认要更改评分卡吗', () => {}); |  | ||||
| }; |  | ||||
| </script> |  | ||||
| @ -1,46 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     ref="defaultCognizanceGridRef" |  | ||||
|     :dense="rating.dense" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="true" |  | ||||
|     :toolbar-actions="[]" |  | ||||
|     :fetch-data-url="Environment.apiContextPath('api/irbs/defaultCognizance')" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     :config-button="false" |  | ||||
|     :columns="[ |  | ||||
|       { name: 'custNo', label: '客户号' }, |  | ||||
|       { name: 'custName', label: '客户名称' }, |  | ||||
|       { name: 'levelHis', label: '违约时评级' }, |  | ||||
|       { name: 'effectiveDate', label: '违约发起时间' }, |  | ||||
|       { name: 'creator', label: '违约发起人' }, |  | ||||
|       { name: 'defaultProcessStatus', label: '违约流程状态' }, |  | ||||
|       { name: 'defalutType', label: '违约认定类型' }, |  | ||||
|     ]" |  | ||||
|     :query-criteria="{ |  | ||||
|       operator: 'and', |  | ||||
|       criteria: [ |  | ||||
|         { |  | ||||
|           fieldName: 'custNo', |  | ||||
|           operator: 'equals', |  | ||||
|           value: rating.ratingData.value['custNo'], |  | ||||
|         }, |  | ||||
|         { |  | ||||
|           fieldName: 'status', |  | ||||
|           operator: 'equals', |  | ||||
|           value: Constant.DEFAULT_PROCESS_STATUS.PASS, |  | ||||
|         }, |  | ||||
|       ], |  | ||||
|     }" |  | ||||
|     :sort-by="['-effectiveDate']" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { Environment } from 'platform-core'; |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Constant } from '../ts/Constant'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,45 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     ref="defaultRebirthGridRef" |  | ||||
|     :dense="rating.dense" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="true" |  | ||||
|     :toolbar-actions="[]" |  | ||||
|     :fetch-data-url="Environment.apiContextPath('api/irbs/defaultRebirth')" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     :config-button="false" |  | ||||
|     :columns="[ |  | ||||
|       { name: 'custNo', label: '客户号' }, |  | ||||
|       { name: 'custName', label: '客户名称' }, |  | ||||
|       { name: 'rebirthEffectiveDate', label: '重生生效时间' }, |  | ||||
|       { name: 'creator', label: '重生发起人' }, |  | ||||
|       { name: 'rebirthProcessStatus', label: '重生流程状态' }, |  | ||||
|       { name: 'defalutRebornType', label: '违约重生类型' }, |  | ||||
|     ]" |  | ||||
|     :query-criteria="{ |  | ||||
|       operator: 'and', |  | ||||
|       criteria: [ |  | ||||
|         { |  | ||||
|           fieldName: 'custNo', |  | ||||
|           operator: 'equals', |  | ||||
|           value: rating.ratingData.value['custNo'], |  | ||||
|         }, |  | ||||
|         { |  | ||||
|           fieldName: 'rebirthProcessStatus', |  | ||||
|           operator: 'equals', |  | ||||
|           value: Constant.DEFAULT_PROCESS_STATUS.PASS, |  | ||||
|         }, |  | ||||
|       ], |  | ||||
|     }" |  | ||||
|     :sort-by="['-rebirthEffectiveDate']" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { Environment } from 'platform-core'; |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Constant } from '../ts/Constant'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,49 +0,0 @@ | |||||
| <template> |  | ||||
|   <div v-if="!Tools.isEmpty(valueComputed)">{{ formatAmt(valueComputed) }} <q-icon :name="iconComputed?.name" :color="iconComputed?.color"></q-icon></div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { computed } from 'vue'; |  | ||||
| import { Tools } from 'platform-core'; |  | ||||
| import { formatAmt } from '../ts/Utils'; |  | ||||
| 
 |  | ||||
| const props = defineProps({ |  | ||||
|   // 本期值 |  | ||||
|   value: { type: Number, default: undefined }, |  | ||||
|   // 上期值 |  | ||||
|   previousPeriod: { type: Number, default: undefined }, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const icon = { |  | ||||
|   equals: { |  | ||||
|     name: 'horizontal_rule', |  | ||||
|     color: 'green', |  | ||||
|   }, |  | ||||
|   up: { |  | ||||
|     name: 'arrow_upward', |  | ||||
|     color: 'blue', |  | ||||
|   }, |  | ||||
|   down: { |  | ||||
|     name: 'arrow_downward', |  | ||||
|     color: 'orange', |  | ||||
|   }, |  | ||||
| }; |  | ||||
| 
 |  | ||||
| const valueComputed = computed(() => { |  | ||||
|   if (!Tools.isEmpty(props.value) && !Tools.isEmpty(props.previousPeriod)) { |  | ||||
|     const result = props.value - props.previousPeriod; |  | ||||
|     return result; |  | ||||
|   } |  | ||||
|   return undefined; |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const iconComputed = computed(() => { |  | ||||
|   if (!Tools.isEmpty(valueComputed.value) && valueComputed.value === 0) { |  | ||||
|     return icon.equals; |  | ||||
|   } else if (!Tools.isEmpty(valueComputed.value) && valueComputed.value > 0) { |  | ||||
|     return icon.up; |  | ||||
|   } else if (!Tools.isEmpty(valueComputed.value) && valueComputed.value < 0) { |  | ||||
|     return icon.down; |  | ||||
|   } |  | ||||
|   return undefined; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,74 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     :dense-body="true" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="true" |  | ||||
|     :dense="true" |  | ||||
|     :fetch-data-url="Environment.apiContextPath('api/irbs/financeReportDetail/query/' + rating.ratingData.value['custId'])" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     :sort-no="true" |  | ||||
|     :config-button="false" |  | ||||
|     :columns="columnsComputed" |  | ||||
|     :query-criteria="props.queryCriteria" |  | ||||
|     :sort-by="['projectCode']" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, onMounted, computed } from 'vue'; |  | ||||
| import { Environment } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import FinanceProjectCompare from './FinanceProjectCompare.vue'; |  | ||||
| import { formatAmt } from '../ts/Utils'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const props = defineProps({ |  | ||||
|   queryCriteria: { type: Object, default: undefined }, |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const columnsComputed = computed(() => { |  | ||||
|   const columns = <any>[ |  | ||||
|     { name: 'code', label: '科目编码' }, |  | ||||
|     { name: 'name', label: '科目名称' }, |  | ||||
|   ]; |  | ||||
|   if (rating.financeReport.value.length > 0) { |  | ||||
|     const columnNames = ['value', 'previousPeriodvalue', 'previousPeriod2value', 'previousPeriod3value']; |  | ||||
|     rating.financeReport.value.forEach((report: any, index: number) => { |  | ||||
|       const year = report['endDate'].substring(0, 4); |  | ||||
|       columns.push({ |  | ||||
|         name: year, |  | ||||
|         label: year, |  | ||||
|         columns: [ |  | ||||
|           { |  | ||||
|             name: columnNames[index], |  | ||||
|             label: '本期值', |  | ||||
|             align: 'right', |  | ||||
|             format: (val, row) => { |  | ||||
|               return formatAmt(val); |  | ||||
|             }, |  | ||||
|           }, |  | ||||
|           { |  | ||||
|             name: year + 'comparePreviousPeriod', |  | ||||
|             label: '比上期', |  | ||||
|             align: 'right', |  | ||||
|             format: (val, row) => { |  | ||||
|               return { |  | ||||
|                 componentType: FinanceProjectCompare, |  | ||||
|                 attrs: { |  | ||||
|                   value: row[columnNames[index]], |  | ||||
|                   previousPeriod: index === columnNames.length - 1 ? undefined : row[columnNames[index + 1]], |  | ||||
|                 }, |  | ||||
|               }; |  | ||||
|             }, |  | ||||
|           }, |  | ||||
|         ], |  | ||||
|       }); |  | ||||
|     }); |  | ||||
|   } |  | ||||
|   return columns; |  | ||||
| }); |  | ||||
| 
 |  | ||||
| onMounted(() => { |  | ||||
|   rating.api.loadFinanceReport(); |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,146 +0,0 @@ | |||||
| <template> |  | ||||
|   <div> |  | ||||
|     <w-grid |  | ||||
|       ref="financeReportGridRef" |  | ||||
|       title="财务报表" |  | ||||
|       :dense="rating.dense" |  | ||||
|       :height="150" |  | ||||
|       :pageable="false" |  | ||||
|       :hide-bottom="true" |  | ||||
|       :auto-fetch-data="false" |  | ||||
|       :fetch-data-url="Environment.apiContextPath('api/irbs/financeReport/getReport')" |  | ||||
|       :checkbox-selection="false" |  | ||||
|       :config-button="false" |  | ||||
|       :columns="[ |  | ||||
|         { name: 'endDate', label: '财报日期', format: Formater.dateOnly() }, |  | ||||
|         // { name: 'type', label: '报表类型', format: Formater.dictionary(rating.dictionary.financeTypeCd) }, |  | ||||
|         { |  | ||||
|           name: 'type', |  | ||||
|           label: '报表类型', |  | ||||
|           format: Formater.dictionary(rating.dictionary.financeTypeCd), |  | ||||
|         }, |  | ||||
|         { name: 'sort', label: '报表类别', format: Formater.dictionary(rating.dictionary.financeSortTypeCd) }, |  | ||||
|         { name: 'auditedInd', label: '是否审计', format: Formater.dictionary(rating.dictionary.financeStatusCd) }, |  | ||||
|         { name: 'caliber', label: '报表口径', format: Formater.dictionary(rating.dictionary.caliberCd) }, |  | ||||
|         { name: 'currency', label: '报表币种', format: Formater.dictionary(rating.dictionary.currencyTypeCd) }, |  | ||||
|         { name: 'userNo', label: '经办人' }, |  | ||||
|         { name: 'remarks', label: '备注' }, |  | ||||
|         { |  | ||||
|           name: 'op', |  | ||||
|           label: '操作', |  | ||||
|           format: opFormat, |  | ||||
|         }, |  | ||||
|       ]" |  | ||||
|     ></w-grid> |  | ||||
|     <w-dialog ref="financeReportDetailDialogRef" title="财报详情" width="80%" height="80%" body-padding="0px 0px 0px 0px"> |  | ||||
|       <w-splitter :size="60" horizontal unit="px" disable class="h-full"> |  | ||||
|         <template #before> |  | ||||
|           <div class="p-1"> |  | ||||
|             <w-info-panel :info="financeReport.otherInfo" :column-num="5" :label-width="150"></w-info-panel> |  | ||||
|           </div> |  | ||||
|         </template> |  | ||||
| 
 |  | ||||
|         <template #after> |  | ||||
|           <div class="flex flex-nowrap items-start h-full"> |  | ||||
|             <div class="flex-none h-full"> |  | ||||
|               <q-tabs v-model="detailTab" vertical indicator-color="amber" active-color="amber"> |  | ||||
|                 <template v-for="report in financeReport.tabsComputed.value" :key="report.value"> |  | ||||
|                   <q-tab :name="report.value" :icon="report.icon" :label="report.label" /> |  | ||||
|                 </template> |  | ||||
|               </q-tabs> |  | ||||
|             </div> |  | ||||
|             <q-separator vertical /> |  | ||||
|             <div class="flex-1 h-full"> |  | ||||
|               <q-tab-panels |  | ||||
|                 v-model="detailTab" |  | ||||
|                 :keep-alive="true" |  | ||||
|                 animated |  | ||||
|                 swipeable |  | ||||
|                 vertical |  | ||||
|                 transition-prev="jump-up" |  | ||||
|                 transition-next="jump-up" |  | ||||
|                 class="h-full" |  | ||||
|               > |  | ||||
|                 <template v-for="report in financeReport.tabsComputed.value" :key="report.value"> |  | ||||
|                   <q-tab-panel :name="report.value" class="h-full p-1"> |  | ||||
|                     <FinanceProjectGrid |  | ||||
|                       :query-criteria="{ |  | ||||
|                         operator: 'and', |  | ||||
|                         criteria: [ |  | ||||
|                           { |  | ||||
|                             fieldName: 'reportId', |  | ||||
|                             operator: 'equals', |  | ||||
|                             value: financeReport.reportId, |  | ||||
|                           }, |  | ||||
|                           { |  | ||||
|                             fieldName: 'projectType', |  | ||||
|                             operator: 'equals', |  | ||||
|                             value: report.value, |  | ||||
|                           }, |  | ||||
|                         ], |  | ||||
|                       }" |  | ||||
|                     ></FinanceProjectGrid> |  | ||||
|                   </q-tab-panel> |  | ||||
|                 </template> |  | ||||
|               </q-tab-panels> |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|         </template> |  | ||||
|       </w-splitter> |  | ||||
|     </w-dialog> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, nextTick, reactive, inject } from 'vue'; |  | ||||
| import { Formater, Environment } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import FinanceProjectGrid from './FinanceProjectGrid.vue'; |  | ||||
| import { FinanceReport, Constant } from '../ts/FinanceReport'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const financeReportGridRef = ref(); |  | ||||
| const getFinanceReportGridRef = () => { |  | ||||
|   return financeReportGridRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setFinanceReportGridRefFunction(getFinanceReportGridRef); |  | ||||
| const financeReportDetailDialogRef = ref(); |  | ||||
| const financeReport = new FinanceReport(); |  | ||||
| 
 |  | ||||
| const splitterModel = ref(60); |  | ||||
| const detailTab = ref(''); |  | ||||
| 
 |  | ||||
| const opFormat = (value, row) => { |  | ||||
|   if (row && row['sort']) { |  | ||||
|     return { |  | ||||
|       componentType: 'q-chip', |  | ||||
|       attrs: { |  | ||||
|         dense: true, |  | ||||
|         color: 'primary', |  | ||||
|         icon: 'visibility', |  | ||||
|         textColor: 'white', |  | ||||
|         square: true, |  | ||||
|         size: rating.dense ? 'xs' : 'md', |  | ||||
|         label: '查 看', |  | ||||
|         onclick: () => { |  | ||||
|           financeReport.reportType.value = row['sort']; |  | ||||
|           if (financeReport.reportType.value === Constant.REPORT_TYPE_COMPANY) { |  | ||||
|             detailTab.value = FinanceReport.reportDetail.c_balance_sheet.value; |  | ||||
|           } else { |  | ||||
|             detailTab.value = FinanceReport.reportDetail.p_balance_sheet.value; |  | ||||
|           } |  | ||||
|           financeReport.reportId = row['id']; |  | ||||
|           financeReportDetailDialogRef.value.show(); |  | ||||
|           financeReport.otherInfo = []; |  | ||||
|           financeReport.otherInfo.push({ label: '财务报表截至日期', value: row['endDate'], format: Formater.dateOnly() }); |  | ||||
|           financeReport.otherInfo.push({ label: '是否经过审计', value: row['auditedInd'], format: Formater.dictionary(rating.dictionary.financeStatusCd) }); |  | ||||
|           financeReport.otherInfo.push({ label: '财务报表类别', value: row['sort'], format: Formater.dictionary(rating.dictionary.financeTypeCd) }); |  | ||||
|           financeReport.otherInfo.push({ label: '财务报表口径', value: row['caliber'], format: Formater.dictionary(rating.dictionary.caliberCd) }); |  | ||||
|           financeReport.otherInfo.push({ label: '财务报表币种', value: row['currency'], format: Formater.dictionary(rating.dictionary.currencyTypeCd) }); |  | ||||
|         }, |  | ||||
|       }, |  | ||||
|     }; |  | ||||
|   } else { |  | ||||
|     return ''; |  | ||||
|   } |  | ||||
| }; |  | ||||
| </script> |  | ||||
| @ -1,39 +0,0 @@ | |||||
| <template> |  | ||||
|   <div class="h-full"> |  | ||||
|     <w-splitter :size="36" horizontal class="h-full" unit="px" disable> |  | ||||
|       <template #before> |  | ||||
|         <q-tabs v-model="tab" inline-label dense indicator-color="amber" align="right" active-color="amber"> |  | ||||
|           <template v-for="report in financeReport.tabsComputed.value" :key="report.value"> |  | ||||
|             <q-tab :name="report.value" :icon="report.icon" :label="report.label" /> |  | ||||
|           </template> |  | ||||
|         </q-tabs> |  | ||||
|       </template> |  | ||||
|       <template #after> |  | ||||
|         <q-tab-panels v-model="tab" :keep-alive="true" animated swipeable vertical transition-prev="jump-up" transition-next="jump-up" class="h-full"> |  | ||||
|           <template v-for="report in financeReport.tabsComputed.value" :key="report.value"> |  | ||||
|             <q-tab-panel :name="report.value" class="h-full p-1"> |  | ||||
|               <FinanceProjectGrid |  | ||||
|                 :query-criteria="{ |  | ||||
|                   fieldName: 'projectType', |  | ||||
|                   operator: 'equals', |  | ||||
|                   value: report.value, |  | ||||
|                 }" |  | ||||
|               ></FinanceProjectGrid> |  | ||||
|             </q-tab-panel> |  | ||||
|           </template> |  | ||||
|         </q-tab-panels> |  | ||||
|       </template> |  | ||||
|     </w-splitter> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, ref } from 'vue'; |  | ||||
| import { Environment, Formater } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import { FinanceReport, Constant } from '../ts/FinanceReport'; |  | ||||
| import FinanceProjectGrid from './FinanceProjectGrid.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const financeReport = new FinanceReport(); |  | ||||
| const tab = ref(FinanceReport.reportDetail.c_balance_sheet.value); |  | ||||
| </script> |  | ||||
| @ -1,29 +0,0 @@ | |||||
| <template> |  | ||||
|   <div v-if="rating.systemParameter.showTotalScore.value"> |  | ||||
|     <span class="pl-[8px]">初评结果</span> |  | ||||
|     <w-info-panel :info="rating.firstRatingData.value" :column-num="4"></w-info-panel> |  | ||||
|   </div> |  | ||||
|   <div v-else> |  | ||||
|     <q-list dense> |  | ||||
|       <q-item> |  | ||||
|         <q-item-section avatar>初评结果</q-item-section> |  | ||||
|         <q-item-section> |  | ||||
|           <RatingLevelSlider v-model="firstRatingLevelComputed"></RatingLevelSlider> |  | ||||
|         </q-item-section> |  | ||||
|       </q-item> |  | ||||
|     </q-list> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, computed } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import RatingLevelSlider from '../../RatingLevelSlider.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const firstRatingLevelComputed = computed(() => { |  | ||||
|   if (rating.firstRatingData.value && rating.firstRatingData.value.length > 0) { |  | ||||
|     return rating.firstRatingData.value[0]['value']; |  | ||||
|   } |  | ||||
|   return undefined; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,51 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     ref="custHistRatingGridRef" |  | ||||
|     :dense="rating.dense" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="true" |  | ||||
|     :toolbar-actions="[]" |  | ||||
|     :fetch-data-url="Environment.apiContextPath('api/irbs/companyRating')" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     :config-button="false" |  | ||||
|     :columns="[ |  | ||||
|       { name: 'id', label: '申请编号' }, |  | ||||
|       { name: 'custNo', label: '客户号' }, |  | ||||
|       { name: 'custName', label: '客户名称' }, |  | ||||
|       // { name: 'modelScore', label: '得分' }, |  | ||||
|       { name: 'modelLevel', label: '系统评级等级' }, |  | ||||
|       { name: 'adjLevel', label: '调整等级' }, |  | ||||
|       { name: 'initLevel', label: '初评等级' }, |  | ||||
|       { name: 'finalLevel', label: '最终等级' }, |  | ||||
|       { name: 'effectiveTime', label: '生效日期', format: Formater.dateOnly() }, |  | ||||
|       { name: 'matureTime', label: '到期日期', format: Formater.dateOnly() }, |  | ||||
|       { name: 'ratingStatus', label: '评级状态', format: Formater.enum(rating.enum.ratingStatus) }, |  | ||||
|       { name: 'launchUser', label: '发起人' }, |  | ||||
|       { name: 'processStatus', label: '状态', format: Formater.enum(rating.enum.ratingProcessStatus) }, |  | ||||
|     ]" |  | ||||
|     :query-criteria="{ |  | ||||
|       operator: 'and', |  | ||||
|       criteria: [ |  | ||||
|         { |  | ||||
|           fieldName: 'custNo', |  | ||||
|           operator: 'equals', |  | ||||
|           value: rating.ratingData.value['custNo'], |  | ||||
|         }, |  | ||||
|         { |  | ||||
|           fieldName: 'processStatus', |  | ||||
|           operator: 'equals', |  | ||||
|           value: Constant.DEFAULT_PROCESS_STATUS.PASS, |  | ||||
|         }, |  | ||||
|       ], |  | ||||
|     }" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { Environment, Formater } from 'platform-core'; |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Constant } from '../ts/Constant'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,33 +0,0 @@ | |||||
| <template> |  | ||||
|   <div class="h-full"> |  | ||||
|     <w-splitter :size="36" horizontal class="h-full" unit="px" disable> |  | ||||
|       <template #before> |  | ||||
|         <q-tabs v-model="tab" inline-label dense indicator-color="amber" align="left" active-color="amber"> |  | ||||
|           <template v-for="item in HistGird.tabs" :key="item.value"> |  | ||||
|             <q-tab :name="item.value" :icon="item.icon" :label="item.label" /> |  | ||||
|           </template> |  | ||||
|         </q-tabs> |  | ||||
|       </template> |  | ||||
|       <template #after> |  | ||||
|         <q-tab-panels v-model="tab" :keep-alive="true" animated swipeable vertical transition-prev="jump-up" transition-next="jump-up" class="h-full"> |  | ||||
|           <template v-for="item in HistGird.tabs" :key="item.value"> |  | ||||
|             <q-tab-panel :name="item.value" class="h-full p-1"> |  | ||||
|               <HistRatingGrid v-if="item.value === HistGird.type.histRating.value"></HistRatingGrid> |  | ||||
|               <DefaultCognizanceGrid v-else-if="item.value === HistGird.type.defaultCognizance.value"></DefaultCognizanceGrid> |  | ||||
|               <DefaultRebirthGrid v-else-if="item.value === HistGird.type.defaultRebirth.value"></DefaultRebirthGrid> |  | ||||
|             </q-tab-panel> |  | ||||
|           </template> |  | ||||
|         </q-tab-panels> |  | ||||
|       </template> |  | ||||
|     </w-splitter> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref } from 'vue'; |  | ||||
| import { HistGird } from '../ts/HistGrid'; |  | ||||
| import HistRatingGrid from './HistRatingGrid.vue'; |  | ||||
| import DefaultCognizanceGrid from './DefaultCognizanceGrid.vue'; |  | ||||
| import DefaultRebirthGrid from './DefaultRebirthGrid.vue'; |  | ||||
| 
 |  | ||||
| const tab = ref(HistGird.type.histRating.value); |  | ||||
| </script> |  | ||||
| @ -1,40 +0,0 @@ | |||||
| <template> |  | ||||
|   <div class="h-full pl-1"> |  | ||||
|     <w-splitter v-if="!rating.cm.isAwaitSubmitProcessStatus.value" :size="rating.readMode ? 100 : 50" horizontal class="h-full" disable :show-separator="false"> |  | ||||
|       <template #before> |  | ||||
|         <w-splitter :size="36" horizontal class="h-full" unit="px" disable :show-separator="false"> |  | ||||
|           <template #before> |  | ||||
|             <q-tabs v-model="histTab" dense no-caps inline-label align="right"> |  | ||||
|               <q-tab name="timeline" icon="query_builder" label="审批时间线" /> |  | ||||
|               <q-tab name="grid" icon="grid_on" label="审批列表" /> |  | ||||
|             </q-tabs> |  | ||||
|           </template> |  | ||||
|           <template #after> |  | ||||
|             <q-tab-panels v-model="histTab" class="p-0 h-full"> |  | ||||
|               <q-tab-panel name="timeline" class="p-0 pt-1 px-2 h-full"> |  | ||||
|                 <Timeline></Timeline> |  | ||||
|               </q-tab-panel> |  | ||||
|               <q-tab-panel name="grid" class="p-0 pt-1 h-full"> |  | ||||
|                 <OpinionGrid></OpinionGrid> |  | ||||
|               </q-tab-panel> |  | ||||
|             </q-tab-panels> |  | ||||
|           </template> |  | ||||
|         </w-splitter> |  | ||||
|       </template> |  | ||||
|       <template #after> |  | ||||
|         <Overturn></Overturn> |  | ||||
|       </template> |  | ||||
|     </w-splitter> |  | ||||
|     <Overturn v-else class="p-1"></Overturn> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, ref } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import OpinionGrid from './OpinionGrid.vue'; |  | ||||
| import Overturn from './Overturn.vue'; |  | ||||
| import Timeline from './Timeline.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const histTab = ref('timeline'); |  | ||||
| </script> |  | ||||
| @ -1,44 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-grid |  | ||||
|     ref="opinionGridRef" |  | ||||
|     :dense="rating.dense" |  | ||||
|     :pageable="false" |  | ||||
|     :hide-bottom="true" |  | ||||
|     :auto-fetch-data="true" |  | ||||
|     :fetch-data-url="histOpinionUrl" |  | ||||
|     :checkbox-selection="false" |  | ||||
|     :config-button="false" |  | ||||
|     :columns="[ |  | ||||
|       { name: 'roleName', label: '岗位名称', width: 150 }, |  | ||||
|       { name: 'userCode', label: '操作人工号', width: 100 }, |  | ||||
|       { name: 'userName', label: '操作人名称', width: 100 }, |  | ||||
|       { name: 'operationOpinion', label: '操作意见', width: 100, format: Formater.dictionary({ items: RatingProcessOperationStatus }) }, |  | ||||
|       { name: 'adjReason', label: '意见说明', width: 200 }, |  | ||||
|       { name: 'lastModifyDate', label: '操作时间', width: 150 }, |  | ||||
|       { name: 'isOverturn', label: '是否推翻', width: 80, format: Formater.yesNo() }, |  | ||||
|       { name: 'overturnType', label: '推翻类型', width: 100, format: Formater.dictionary(rating.dictionary.overturnType) }, |  | ||||
|       { name: 'suggestLevel', label: '建议等级', width: 100 }, |  | ||||
|       { name: 'fileCount', label: '附件列表', width: 100 }, |  | ||||
|     ]" |  | ||||
|     :query-criteria="{ |  | ||||
|       fieldName: 'ratingId', |  | ||||
|       operator: 'equals', |  | ||||
|       value: rating.ratingData.value['id'], |  | ||||
|     }" |  | ||||
|     :sort-by="['-lastModifyDate']" |  | ||||
|   ></w-grid> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, ref } from 'vue'; |  | ||||
| import { Environment, Formater } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import { RatingProcessOperationStatus } from '../../CustRating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const overturnFormRef = ref(); |  | ||||
| const getOverturnFormRef = () => { |  | ||||
|   return overturnFormRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setOverturnFormRefFunction(getOverturnFormRef); |  | ||||
| const histOpinionUrl = Environment.apiContextPath('api/irbs/ratingOverturn'); |  | ||||
| </script> |  | ||||
| @ -1,77 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-card-panel v-bind="panelAttrsComputed"> |  | ||||
|     <div class="flex flex-row gap-4"> |  | ||||
|       <div v-if="rating.cm.isAwaitSubmitProcessStatus.value" class="basis-1/4"> |  | ||||
|         <w-info-panel :info="rating.overturnTipData.value" :column-num="1"></w-info-panel> |  | ||||
|       </div> |  | ||||
|       <div :class="rating.cm.isAwaitSubmitProcessStatus.value ? 'basis-2/3' : 'flex-1'"> |  | ||||
|         <w-form |  | ||||
|           ref="overturnFormRef" |  | ||||
|           :fields="[ |  | ||||
|             { label: '附件', name: 'file', type: 'w-file' }, |  | ||||
|             { label: '是否推翻', name: 'isOverturn', type: 'w-checkbox' }, |  | ||||
|             { |  | ||||
|               label: '推翻类型', |  | ||||
|               name: 'overturnType', |  | ||||
|               type: 'w-select', |  | ||||
|               options: Options.dictionary(rating.dictionary.overturnType), |  | ||||
|               requiredIf: true, |  | ||||
|               showIf: (args) => { |  | ||||
|                 if (args?.form && args.form.getFieldValue('isOverturn')) { |  | ||||
|                   return true; |  | ||||
|                 } |  | ||||
|                 return false; |  | ||||
|               }, |  | ||||
|             }, |  | ||||
|             { |  | ||||
|               label: '建议等级', |  | ||||
|               name: 'suggestLevel', |  | ||||
|               type: 'w-select', |  | ||||
|               options: RatingLevelOptions, |  | ||||
|               requiredIf: true, |  | ||||
|               showIf: (args) => { |  | ||||
|                 if (args?.form && args.form.getFieldValue('isOverturn')) { |  | ||||
|                   return true; |  | ||||
|                 } |  | ||||
|                 return false; |  | ||||
|               }, |  | ||||
|             }, |  | ||||
|             { |  | ||||
|               label: '意见说明', |  | ||||
|               name: 'adjReason', |  | ||||
|               type: 'w-textarea', |  | ||||
|               requiredIf: true, |  | ||||
|             }, |  | ||||
|           ]" |  | ||||
|           :cols-num="1" |  | ||||
|         ></w-form> |  | ||||
|       </div> |  | ||||
|     </div> |  | ||||
|   </w-card-panel> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { Options } from 'platform-core'; |  | ||||
| import { computed, ref, inject } from 'vue'; |  | ||||
| import { RatingLevelOptions } from '../../CustRating'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const overturnFormRef = ref(); |  | ||||
| const getOverturnFormRef = () => { |  | ||||
|   return overturnFormRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setOverturnFormRefFunction(getOverturnFormRef); |  | ||||
| const panelAttrsComputed = computed(() => { |  | ||||
|   if (rating.cm.isAwaitSubmitProcessStatus.value) { |  | ||||
|     return { |  | ||||
|       label: '评级推翻', |  | ||||
|       icon: 'model_training', |  | ||||
|     }; |  | ||||
|   } else { |  | ||||
|     return { |  | ||||
|       label: '审批意见', |  | ||||
|       icon: 'comment', |  | ||||
|     }; |  | ||||
|   } |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,106 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="titleSplitterModel" horizontal unit="px" disable class="h-full"> |  | ||||
|     <template #before> |  | ||||
|       <w-card-panel :bordered="false" :title-mode="true" icon="scatter_plot" :icon-attrs="{ color: 'green' }" color="green"> |  | ||||
|         <template #label> |  | ||||
|           <div class="flex justify-between"> |  | ||||
|             <div> |  | ||||
|               定性分析<q-badge v-if="existsWaitSelectComputed" color="red" floating transparent class="qa-badge">{{ |  | ||||
|                 rating.waitSelectFields.value.length |  | ||||
|               }}</q-badge> |  | ||||
|             </div> |  | ||||
|             <q-toggle v-if="showToggleComputed" v-model="qaMode" color="blue" dense size="40px" icon="bi-quora" label="问卷模式" /> |  | ||||
|             <q-toggle v-if="props.readOnly" v-model="showOptionsModel" color="blue" dense size="40px" icon="hdr_auto" label="显示全部选项" /> |  | ||||
|           </div> |  | ||||
|         </template> |  | ||||
|       </w-card-panel> |  | ||||
|     </template> |  | ||||
|     <template #after> |  | ||||
|       <w-form |  | ||||
|         v-show="showQaPanelComputed" |  | ||||
|         ref="qa-qualFormRef" |  | ||||
|         :cols-num="1" |  | ||||
|         :fields="qaFormFieldComputed" |  | ||||
|         class="px-1 py-1" |  | ||||
|         @update-value="qaFormUpdateValue" |  | ||||
|       ></w-form> |  | ||||
|       <w-form |  | ||||
|         v-show="!showQaPanelComputed" |  | ||||
|         ref="qualitativeFormRef" |  | ||||
|         :fields="qualFormFieldsComputed" |  | ||||
|         :cols-num="1" |  | ||||
|         :y-gap="10" |  | ||||
|         class="pl-1 py-1" |  | ||||
|         @update-value="formUpdateValue" |  | ||||
|       ></w-form> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, ref, computed } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| 
 |  | ||||
| const qualitativeFormRef = ref(); |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const titleSplitterModel = ref(34); |  | ||||
| const getQualitativeFormRef = () => { |  | ||||
|   return qualitativeFormRef.value; |  | ||||
| }; |  | ||||
| rating.refs.setQualitativeFormRefFunction(getQualitativeFormRef); |  | ||||
| 
 |  | ||||
| const props = defineProps({ |  | ||||
|   // 问答模式 |  | ||||
|   qualQaMode: { type: Boolean, default: true }, |  | ||||
|   // 只读模式 |  | ||||
|   readOnly: { type: Boolean, default: false }, |  | ||||
|   // 显示所有选项 |  | ||||
|   showOptions: { type: Boolean, default: false }, |  | ||||
| }); |  | ||||
| const qaMode = ref(props.readOnly ? false : props.qualQaMode); |  | ||||
| const showOptionsModel = ref(props.showOptions); |  | ||||
| 
 |  | ||||
| const qaFormFieldComputed = computed(() => { |  | ||||
|   const result = <any>[]; |  | ||||
|   if (rating.waitSelectFields.value?.length > 0) { |  | ||||
|     result.push({ |  | ||||
|       type: 'w-form-group', |  | ||||
|       label: rating.waitSelectFields.value[0]['group'], |  | ||||
|       mode: 'card', |  | ||||
|       fields: [rating.waitSelectFields.value[0]['field']], |  | ||||
|     }); |  | ||||
|   } |  | ||||
|   return result; |  | ||||
| }); |  | ||||
| const showQaPanelComputed = computed(() => { |  | ||||
|   return showToggleComputed.value && qaMode.value; |  | ||||
| }); |  | ||||
| const showToggleComputed = computed(() => { |  | ||||
|   return props.qualQaMode && existsWaitSelectComputed.value; |  | ||||
| }); |  | ||||
| const existsWaitSelectComputed = computed(() => { |  | ||||
|   return rating.waitSelectFields.value.length > 0 && !props.readOnly; |  | ||||
| }); |  | ||||
| const qualFormFieldsComputed = computed(() => { |  | ||||
|   if (showOptionsModel.value) { |  | ||||
|     return rating.qualFormData.value; |  | ||||
|   } |  | ||||
|   return rating.qualSimpleOptionData.value; |  | ||||
| }); |  | ||||
| 
 |  | ||||
| const qaFormUpdateValue = (args) => { |  | ||||
|   qualitativeFormRef.value.setFieldValue(args.fieldName, args.fieldValue); |  | ||||
|   rating.waitSelectFields.value = rating.waitSelectFields.value.slice(1); |  | ||||
| }; |  | ||||
| const formUpdateValue = (args) => { |  | ||||
|   const result = rating.waitSelectFields.value.filter((field) => field.field['name'] !== args.fieldName); |  | ||||
|   rating.waitSelectFields.value = result; |  | ||||
| }; |  | ||||
| </script> |  | ||||
| <style lang="css"> |  | ||||
| .qa-badge { |  | ||||
|   position: relative; |  | ||||
|   top: -7px; |  | ||||
|   right: -2px; |  | ||||
|   cursor: inherit; |  | ||||
| } |  | ||||
| </style> |  | ||||
| @ -1,51 +0,0 @@ | |||||
| <template> |  | ||||
|   <w-splitter :size="34" horizontal unit="px" disable class="h-full"> |  | ||||
|     <template #before> |  | ||||
|       <w-card-panel label="定量分析" :bordered="false" :title-mode="true" icon="bar_chart" :icon-attrs="{ color: 'teal' }" color="teal"></w-card-panel> |  | ||||
|     </template> |  | ||||
|     <template #after> |  | ||||
|       <div v-if="rating.systemParameter.showTotalScore.value" class="p-1"> |  | ||||
|         <w-card-panel :info="rating.quanData.value"></w-card-panel> |  | ||||
|       </div> |  | ||||
|       <div v-if="rating.systemParameter.showIndex.value" class="rating-quan"> |  | ||||
|         <q-list> |  | ||||
|           <template v-for="(values, key, a) in rating.quanScoreDtlData.value" :key="a"> |  | ||||
|             <!-- <q-item-label header><q-icon name="toc" size="25px" />定量指标详情</q-item-label> --> |  | ||||
|             <template v-for="(dtl, index) in values" :key="index"> |  | ||||
|               <q-item> |  | ||||
|                 <q-item-section> |  | ||||
|                   <q-item-label>{{ dtl['INDEX_NAME'] }}</q-item-label> |  | ||||
|                   <q-item-label caption> |  | ||||
|                     {{ round(dtl['INDEX_VALUE'], 2) }} |  | ||||
|                   </q-item-label> |  | ||||
|                 </q-item-section> |  | ||||
|                 <q-item-section v-if="rating.systemParameter.showIndexScore.value && !Tools.isEmpty(dtl['INDEX_SCORE'])" side> |  | ||||
|                   <q-chip :clickable="false" :ripple="false" color="green" text-color="white"> |  | ||||
|                     {{ round(dtl['INDEX_SCORE'], 2) }} |  | ||||
|                   </q-chip> |  | ||||
|                 </q-item-section> |  | ||||
|               </q-item> |  | ||||
|             </template> |  | ||||
|           </template> |  | ||||
|         </q-list> |  | ||||
|       </div> |  | ||||
|     </template> |  | ||||
|   </w-splitter> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { Tools } from 'platform-core'; |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import { round } from '../ts/Utils'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| <style lang="css"> |  | ||||
| .rating-quan { |  | ||||
|   padding-top: 10px; |  | ||||
| } |  | ||||
| .rating-quan .text-caption { |  | ||||
|   font-size: 1rem; |  | ||||
|   color: #2196f3; |  | ||||
| } |  | ||||
| </style> |  | ||||
| @ -1,20 +0,0 @@ | |||||
| <template> |  | ||||
|   <div class="h-full"> |  | ||||
|     <w-splitter :size="25" :separator-color="rating.separatorColor" class="h-full"> |  | ||||
|       <template #before> |  | ||||
|         <QuanAnalysis></QuanAnalysis> |  | ||||
|       </template> |  | ||||
|       <template #after> |  | ||||
|         <QualAnalysis :qual-qa-mode="rating.systemParameter.qualQaMode.value" :show-options="true"></QualAnalysis> |  | ||||
|       </template> |  | ||||
|     </w-splitter> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import QuanAnalysis from './QuanAnalysis.vue'; |  | ||||
| import QualAnalysis from './QualAnalysis.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| </script> |  | ||||
| @ -1,36 +0,0 @@ | |||||
| <template> |  | ||||
|   <div v-if="rating.systemParameter.reportShowScoreDtl.value" class="h-full"> |  | ||||
|     <w-splitter :size="25" :separator-color="rating.separatorColor"> |  | ||||
|       <template #before> |  | ||||
|         <QuanAnalysis></QuanAnalysis> |  | ||||
|       </template> |  | ||||
| 
 |  | ||||
|       <template #after> |  | ||||
|         <w-splitter v-if="splitComputed" :size="65" class="h-full" :separator-color="rating.separatorColor"> |  | ||||
|           <template #before> |  | ||||
|             <QualAnalysis :qual-qa-mode="false" :read-only="true"></QualAnalysis> |  | ||||
|           </template> |  | ||||
|           <template #after> |  | ||||
|             <AdjustItemIndex></AdjustItemIndex> |  | ||||
|           </template> |  | ||||
|         </w-splitter> |  | ||||
|         <QualAnalysis v-else :qual-qa-mode="false" :read-only="true"></QualAnalysis> |  | ||||
|       </template> |  | ||||
|     </w-splitter> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { inject, computed } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import QuanAnalysis from './QuanAnalysis.vue'; |  | ||||
| import QualAnalysis from './QualAnalysis.vue'; |  | ||||
| import AdjustItemIndex from './AdjustItemIndex.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const splitComputed = computed(() => { |  | ||||
|   if (rating.adjustItemScoreDtlData.value && Object.keys(rating.adjustItemScoreDtlData.value).length > 0) { |  | ||||
|     return true; |  | ||||
|   } |  | ||||
|   return false; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,34 +0,0 @@ | |||||
| <template> |  | ||||
|   <div class="h-full"> |  | ||||
|     <w-splitter :size="splitterSizeComputed" :limits="[0, Infinity]" horizontal unit="px" disable class="h-full"> |  | ||||
|       <template #before> |  | ||||
|         <ReportRating></ReportRating> |  | ||||
|       </template> |  | ||||
|       <template #after> |  | ||||
|         <w-splitter :size="70" horizontal :separator-color="rating.separatorColor"> |  | ||||
|           <template #before> |  | ||||
|             <ReportIndex></ReportIndex> |  | ||||
|           </template> |  | ||||
|           <template #after> |  | ||||
|             <HistTab></HistTab> |  | ||||
|           </template> |  | ||||
|         </w-splitter> |  | ||||
|       </template> |  | ||||
|     </w-splitter> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { computed, inject } from 'vue'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import HistTab from './HistTab.vue'; |  | ||||
| import ReportIndex from './ReportIndex.vue'; |  | ||||
| import ReportRating from './ReportRating.vue'; |  | ||||
| 
 |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const splitterSizeComputed = computed(() => { |  | ||||
|   if (rating.showAllRatingInfoModel.value) { |  | ||||
|     return 125; |  | ||||
|   } |  | ||||
|   return 40; |  | ||||
| }); |  | ||||
| </script> |  | ||||
| @ -1,157 +0,0 @@ | |||||
| <template> |  | ||||
|   <!-- <w-card-panel label="评级结果" :bordered="false"> |  | ||||
|     <div class="flex"> |  | ||||
|       <div class="flex-1 text-center"> |  | ||||
|         <div>模型名称</div> |  | ||||
|         <div :class="valueClassComputed"> |  | ||||
|           <q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['modelName']" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|       <div class="flex-1 text-center"> |  | ||||
|         <div>模型级别</div> |  | ||||
|         <div :class="valueClassComputed"> |  | ||||
|           <q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['modelLevel']" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|       <div class="flex-1 text-center"> |  | ||||
|         <div>调整后级别</div> |  | ||||
|         <div v-if="rating.ratingData.value['adjLevel']" :class="valueClassComputed"> |  | ||||
|           <q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['adjLevel']" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|       <div class="flex-1 text-center"> |  | ||||
|         <div>推翻级别</div> |  | ||||
|         <div v-if="rating.ratingData.value['tf']" :class="valueClassComputed"> |  | ||||
|           <q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['tf']" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|       <div class="flex-1 text-center"> |  | ||||
|         <div>最终认定级别</div> |  | ||||
|         <div v-if="rating.ratingData.value['finalLevel']" :class="valueClassComputed"> |  | ||||
|           <q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['finalLevel']" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|       <div class="flex-1 text-center"> |  | ||||
|         <div>客户经理</div> |  | ||||
|         <div v-if="rating.ratingData.value['managerName']" :class="valueClassComputed"> |  | ||||
|           <q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['managerName']" /> |  | ||||
|         </div> |  | ||||
|       </div> |  | ||||
|     </div> |  | ||||
|   </w-card-panel> --> |  | ||||
|   <div class="flex"> |  | ||||
|     <div class="flex-1"> |  | ||||
|       <div :class="classComputed"> |  | ||||
|         <div :class="itemClassComputed"> |  | ||||
|           <div :class="labelClassComputed">模型名称:</div> |  | ||||
|           <div :class="valueClassComputed">{{ rating.ratingData.value['modelName'] }}</div> |  | ||||
|         </div> |  | ||||
|         <div :class="itemClassComputed"> |  | ||||
|           <div :class="labelClassComputed">模型评级等级:</div> |  | ||||
|           <div :class="valueClassComputed" @mouseover="handleHover('.rr-modelLevel', rating.ratingData.value['modelLevel'])" @mouseout="handleOut"> |  | ||||
|             <span class="rr-modelLevel underline">{{ rating.ratingData.value['modelLevel'] }}</span> |  | ||||
|           </div> |  | ||||
|         </div> |  | ||||
|         <div :class="itemClassComputed"> |  | ||||
|           <div :class="labelClassComputed">调整后级别:</div> |  | ||||
|           <div :class="valueClassComputed" @mouseover="handleHover('.rr-adjLevel', rating.ratingData.value['adjLevel'])" @mouseout="handleOut"> |  | ||||
|             <span class="rr-adjLevel underline">{{ rating.ratingData.value['adjLevel'] }}</span> |  | ||||
|           </div> |  | ||||
|         </div> |  | ||||
|         <div :class="itemClassComputed"> |  | ||||
|           <div :class="labelClassComputed">最终认定级别:</div> |  | ||||
|           <div :class="valueClassComputed" @mouseover="handleHover('.rr-finalLevel', rating.ratingData.value['finalLevel'])" @mouseout="handleOut"> |  | ||||
|             <span class="rr-finalLevel underline">{{ rating.ratingData.value['finalLevel'] }}</span> |  | ||||
|           </div> |  | ||||
|         </div> |  | ||||
|         <div :class="itemClassComputed"> |  | ||||
|           <div :class="labelClassComputed">客户经理:</div> |  | ||||
|           <div :class="valueClassComputed">{{ rating.ratingData.value['managerName'] }}</div> |  | ||||
|         </div> |  | ||||
|         <template v-if="rating.showAllRatingInfoModel.value"> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">初始级别:</div> |  | ||||
|             <div :class="valueClassComputed" @mouseover="handleHover('.rr-initLevel', rating.ratingData.value['initLevel'])" @mouseout="handleOut"> |  | ||||
|               <span class="rr-initLevel underline">{{ rating.ratingData.value['initLevel'] }}</span> |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">上一次建议级别:</div> |  | ||||
|             <div :class="valueClassComputed" @mouseover="handleHover('.rr-spLevel', rating.ratingData.value['spLevel'])" @mouseout="handleOut"> |  | ||||
|               <span class="rr-spLevel underline">{{ rating.ratingData.value['spLevel'] }}</span> |  | ||||
|             </div> |  | ||||
|           </div> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">评级发起日期:</div> |  | ||||
|             <div :class="valueClassComputed" v-html="Formater.dateOnly()(rating.ratingData.value['startTime'])"></div> |  | ||||
|           </div> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">评级生效日期:</div> |  | ||||
|             <div :class="valueClassComputed" v-html="Formater.dateOnly()(rating.ratingData.value['effectiveTime'])"></div> |  | ||||
|           </div> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">评级到期日期:</div> |  | ||||
|             <div :class="valueClassComputed" v-html="Formater.dateOnly()(rating.ratingData.value['matureTime'])"></div> |  | ||||
|           </div> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">评级状态:</div> |  | ||||
|             <div :class="valueClassComputed">{{ Formater.enum(rating.enum.ratingStatus)(rating.ratingData.value['ratingStatus']) }}</div> |  | ||||
|           </div> |  | ||||
|           <div :class="itemClassComputed"> |  | ||||
|             <div :class="labelClassComputed">流程状态:</div> |  | ||||
|             <div :class="valueClassComputed">{{ Formater.enum(rating.enum.ratingProcessStatus)(rating.ratingData.value['processStatus']) }}</div> |  | ||||
|           </div> |  | ||||
|         </template> |  | ||||
|       </div> |  | ||||
|     </div> |  | ||||
|     <div class="flex-none pr-1 pt-1"> |  | ||||
|       <q-btn |  | ||||
|         flat |  | ||||
|         round |  | ||||
|         color="primary" |  | ||||
|         size="sm" |  | ||||
|         :icon="rating.showAllRatingInfoModel.value ? 'bi-arrow-up-circle-fill' : 'bi-arrow-down-circle-fill'" |  | ||||
|         @click="rating.showAllRatingInfoModel.value = !rating.showAllRatingInfoModel.value" |  | ||||
|       /> |  | ||||
|     </div> |  | ||||
|     <q-popup-proxy v-model="ratingLevelShowModel" :target="ratingLevelTarget" no-parent-event> |  | ||||
|       <div style="height: 80px; width: 650px; padding: 20px 10px 10px 20px"> |  | ||||
|         <RatingLevelSlider v-model="ratingLevel"></RatingLevelSlider> |  | ||||
|       </div> |  | ||||
|     </q-popup-proxy> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, inject, computed } from 'vue'; |  | ||||
| import { Formater } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import RatingLevelSlider from '../../RatingLevelSlider.vue'; |  | ||||
| 
 |  | ||||
| const ratingLevelShowModel = ref(false); |  | ||||
| const ratingLevel = ref(''); |  | ||||
| const ratingLevelTarget = ref(''); |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const itemClassComputed = computed(() => { |  | ||||
|   return 'flex items-center'; |  | ||||
| }); |  | ||||
| const labelClassComputed = computed(() => { |  | ||||
|   return 'flex-none text-gray-500'; |  | ||||
| }); |  | ||||
| const valueClassComputed = computed(() => { |  | ||||
|   return 'flex-1 text-2xl'; |  | ||||
| }); |  | ||||
| const classComputed = computed(() => { |  | ||||
|   if (rating.showAllRatingInfoModel) { |  | ||||
|     return 'grid grid-cols-5 gap-3 pl-3 pt-1'; |  | ||||
|   } |  | ||||
|   return 'grid grid-cols-5 gap-x-3 pl-3 pt-1'; |  | ||||
| }); |  | ||||
| const handleHover = (target_, ratingLevel_: any) => { |  | ||||
|   ratingLevel.value = ratingLevel_; |  | ||||
|   ratingLevelTarget.value = target_; |  | ||||
|   ratingLevelShowModel.value = true; |  | ||||
| }; |  | ||||
| const handleOut = () => { |  | ||||
|   ratingLevelShowModel.value = false; |  | ||||
| }; |  | ||||
| </script> |  | ||||
| @ -1,82 +0,0 @@ | |||||
| <template> |  | ||||
|   <div class="rating-timeline"> |  | ||||
|     <div v-if="timelineData.length < 1" style="display: flex; justify-content: center; align-items: center; height: 100%"> |  | ||||
|       <q-icon size="2em" name="info" />{{ $t('tip.noData') }} |  | ||||
|     </div> |  | ||||
|     <q-timeline v-else layout="dense" side="right" color="secondary"> |  | ||||
|       <template v-for="(opinion, index) in timelineData" :key="index"> |  | ||||
|         <q-timeline-entry side="left" :color="timelineEntryColor(opinion)"> |  | ||||
|           <div style="background-color: #f9f9f9"> |  | ||||
|             {{ opinion['adjReason'] }} |  | ||||
|           </div> |  | ||||
|           <template #subtitle> |  | ||||
|             <div class="flex justify-between"> |  | ||||
|               <span class="text-sm">{{ timelineTitleFormat(opinion) }}</span> |  | ||||
|               <div class="flex gap-x-2"> |  | ||||
|                 <span>{{ opinion['userName'] }}</span> |  | ||||
|                 <span class="text-blue-grey-6">7分钟以前</span> |  | ||||
|               </div> |  | ||||
|             </div> |  | ||||
|           </template> |  | ||||
|         </q-timeline-entry> |  | ||||
|       </template> |  | ||||
|     </q-timeline> |  | ||||
|   </div> |  | ||||
| </template> |  | ||||
| <script setup lang="ts"> |  | ||||
| import { ref, onMounted, inject } from 'vue'; |  | ||||
| import { $t, axios, Environment } from 'platform-core'; |  | ||||
| import { Rating } from '../ts/Rating'; |  | ||||
| import { RatingProcessOperationStatus } from '../../CustRating'; |  | ||||
| 
 |  | ||||
| const timelineData = ref([]); |  | ||||
| const rating = <Rating>inject('rating'); |  | ||||
| const histOpinionUrl = Environment.apiContextPath('api/irbs/ratingOverturn'); |  | ||||
| const timelineTitleFormat = (opinion: any) => { |  | ||||
|   const findResult = RatingProcessOperationStatus.find((item) => item['value'] === opinion['operationOpinion']); |  | ||||
|   if (findResult) { |  | ||||
|     return findResult['label']; |  | ||||
|   } |  | ||||
|   return ''; |  | ||||
| }; |  | ||||
| const timelineSubTitleFormat = (opinion: any) => { |  | ||||
|   return opinion['userName'] + ' ' + timelineTitleFormat(opinion) + ' ' + '7分钟以前'; |  | ||||
| }; |  | ||||
| const timelineEntryColor = (opinion: any) => { |  | ||||
|   const operator = opinion['operationOpinion']; |  | ||||
|   if (operator === '20') { |  | ||||
|     return 'red'; |  | ||||
|   } else if (operator === '30' || operator === '40') { |  | ||||
|     return 'orange'; |  | ||||
|   } |  | ||||
|   return 'secondary'; |  | ||||
| }; |  | ||||
| 
 |  | ||||
| onMounted(() => { |  | ||||
|   const urlSearchParams = new URLSearchParams({ sortBy: ['-lastModifyDate'] }); |  | ||||
|   urlSearchParams.append('pageable', 'false'); |  | ||||
|   const criteria = { |  | ||||
|     fieldName: 'ratingId', |  | ||||
|     operator: 'equals', |  | ||||
|     value: rating.ratingData.value['id'], |  | ||||
|   }; |  | ||||
|   urlSearchParams.append('criteria', JSON.stringify(criteria)); |  | ||||
|   axios.get(histOpinionUrl, { params: urlSearchParams }).then((resp) => { |  | ||||
|     if (resp['code'] === 200) { |  | ||||
|       timelineData.value = resp.data.content; |  | ||||
|     } |  | ||||
|   }); |  | ||||
| }); |  | ||||
| </script> |  | ||||
| <style lang="css"> |  | ||||
| .rating-timeline .q-timeline--dense--right .q-timeline__entry { |  | ||||
|   padding-left: 25px; |  | ||||
| } |  | ||||
| .rating-timeline .q-timeline__title { |  | ||||
|   margin-top: 0; |  | ||||
|   margin-bottom: 0px; |  | ||||
| } |  | ||||
| .rating-timeline .q-timeline__content { |  | ||||
|   padding-bottom: 10px; |  | ||||
| } |  | ||||
| </style> |  | ||||
								
									
										File diff suppressed because one or more lines are too long
									
								
							
						
					
					Loading…
					
					
				
		Reference in new issue