riskControlConfig.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. <template>
  2. <div class="layout-container">
  3. <!-- 菜单栏 -->
  4. <From :form-items="dynamicFormItems" is_add_button="新增风控配置" @addForm="edit" @formSubmitted="handleFormSubmitted"
  5. @formReset="handleFormReset" />
  6. <!-- 表格 -->
  7. <div class="layout-container">
  8. <Table @getTableData="changeTableData" v-model:page="page" ref="table" :data="tableData"
  9. @selection-change="handleSelectionChange">
  10. <!-- <el-table-column prop="index" label="序号" width="60" /> -->
  11. <el-table-column prop="enabled" label="是否启用" width="90">
  12. <template #default="scope">
  13. <el-tag :type="scope.row.enabled === 1 ? 'success' : 'danger'" effect="dark">
  14. {{ getDictionaryName('enabled',scope.row.enabled) || '未启用' }}
  15. </el-tag>
  16. </template>
  17. </el-table-column>
  18. <el-table-column prop="appNames" label="关联应用" width="120">
  19. <template #default="scope">
  20. {{scope.row.canModify? scope.row.appNames : '系统配置全应用生效'}}
  21. </template>
  22. </el-table-column>
  23. <el-table-column prop="appIds" label="关联应用ID" width="150">
  24. <template #default="scope">
  25. {{scope.row.canModify? scope.row.appIds : '系统配置全应用生效'}}
  26. </template>
  27. </el-table-column>
  28. <el-table-column prop="templateCode" label="配置编码" width="90" />
  29. <el-table-column prop="templateContent" label="配置内容" width="200">
  30. <template #default="scope">
  31. <el-popover
  32. class="box-item"
  33. :title="`${scope.row.templateName}的配置内容`"
  34. :width="400"
  35. placement="top-start"
  36. >
  37. <template #reference>
  38. {{ scope.row.templateContent }}
  39. </template>
  40. <div v-html="scope.row.templateContent.split(',').filter(Boolean).map(item => item.trim()).join('<br/>')"></div>
  41. </el-popover>
  42. </template>
  43. </el-table-column>
  44. <el-table-column prop="allSatisfy" label="条件范围" width="100">
  45. <template #default="scope">
  46. {{getDictionaryName('all_satisfy', scope.row.allSatisfy)}}
  47. </template>
  48. </el-table-column>
  49. <el-table-column prop="effectNode" label="业务节点" width="100">
  50. <template #default="scope">
  51. {{getDictionaryName('effect_node', scope.row.effectNode)}}
  52. </template>
  53. </el-table-column>
  54. <el-table-column prop="templateId" label="配置模版ID" width="160" />
  55. <el-table-column prop="templateName" label="配置名称" width="100" />
  56. <el-table-column prop="createTime" label="创建时间" width="160">
  57. <template #default="scope">
  58. {{ convertUTCToBeijing(scope.row.createTime) }}
  59. </template>
  60. </el-table-column>
  61. <el-table-column prop="nickName" label="创建人" width="90" />
  62. <el-table-column prop="updateTime" label="修改时间" width="160">
  63. <template #default="scope">
  64. {{ convertUTCToBeijing(scope.row.updateTime) }}
  65. </template>
  66. </el-table-column>
  67. <el-table-column prop="updateNickName" label="修改者" width="90" />
  68. <el-table-column label="操作" width="150" fixed="right">
  69. <template #default="scope">
  70. <div class="button">
  71. <el-button class="button-item" type="primary" style="margin-bottom: 5px;" @click="edit(scope.row)">
  72. 编辑
  73. </el-button>
  74. <el-button v-if="scope.row.canModify" class="button-item" type="success" style="margin-bottom: 5px;" @click="relativeApp(scope.row)">
  75. 关联应用
  76. </el-button>
  77. <el-button v-if="scope.row.canModify" :type="scope.row.enabled ? 'danger' : ''" class="button-item" style="margin-bottom: 5px;"
  78. @click="enabledConfig(scope.row)">
  79. {{scope.row.enabled ? '关闭' : '开启'}}
  80. </el-button>
  81. </div>
  82. </template>
  83. </el-table-column>
  84. </Table>
  85. </div>
  86. <!-- 操作弹窗 -->
  87. <ConfigForm :layer="layer" @confirm="submit" @close="close" />
  88. <Layer :layer="layer1" @confirm="submit1(ruleForm)" @close="layer1.show = false">
  89. <el-form :model="formEdit" :rules="rules" ref="ruleForm" label-width="160px" style="margin-right:30px;">
  90. <el-form-item required label="应用列表:" prop="appList">
  91. <el-select multiple v-model="formEdit.appList" placeholder="请选择类型" filterable style="width: 400px;">
  92. <el-option v-for="item in appListData" :key="item.appId" :label="item.appName"
  93. :value="item.appId"></el-option>
  94. </el-select>
  95. </el-form-item>
  96. </el-form>
  97. </Layer>
  98. </div>
  99. </template>
  100. <script setup>
  101. import { onBeforeMount, ref, nextTick, reactive } from "vue";
  102. import From from "@/components/from/index.vue";
  103. import Table from "@/components/table/index.vue";
  104. import Layer from '@/components/layer/index.vue'
  105. import ConfigForm from './components/configForm.vue'
  106. import { ElMessage } from 'element-plus'
  107. import {
  108. riskConfigList, riskRelativeApps, riskSaveConfig, riskOptions,
  109. riskEnabledConfig, riskTemplateView, riskUpdateConfig
  110. } from '@/api/riskModule.js'
  111. import { getEnabledList } from '@/api/userModule.js'
  112. import { convertUTCToBeijing } from '@/utils/index.js'
  113. import { useGetDictList } from '@/hooks/useGetDictList.js'
  114. import { useStore } from 'vuex'
  115. const store = useStore()
  116. const { dictData, loadDictData, getOptions, getDictionaryName } = useGetDictList();
  117. const form = ref(null);
  118. const tableData = ref([]);
  119. // 分页参数, 供table使用
  120. const page = reactive({
  121. pageNum: 1,
  122. pageSize: 20,
  123. total: 0,
  124. });
  125. const formSearch = ref({
  126. appId: '',// 渠道来源关联的应用ID
  127. available: null,//是否生效-
  128. configList: null,// 风控配置列表
  129. channelId: null,//渠道商ID
  130. configId: '',// 配置ID
  131. configType: 0,// 配置类型 1-输入框 2-选择框 3-日期
  132. configVal: '',// 配置值
  133. fieldDesc: '',// 字段描述
  134. fieldName: '',// 字段名称
  135. multy: null, //是否多个
  136. createTime: '',// 创建时间
  137. createUserId: '',// 创建人ID-
  138. defaultParam: '',// 默认参数-
  139. updateParam: null,// 用户类型
  140. updateTime: null,// 用户类型
  141. updateUserId: null,// 用户类型
  142. limit: 20,// 当前页数量(查询量)
  143. page: 1,// 当前页码
  144. pageSizes: 20,// 总页数
  145. superAdmin: null,//
  146. total: null,// 总条数
  147. });
  148. const dynamicFormItems = ref([])
  149. onBeforeMount(async () => {
  150. await getEnabledListData()
  151. await settingData()
  152. await getList();
  153. await getRiskOptions()
  154. });
  155. // 获取缓存数据设置筛选数据
  156. const settingData = () => {
  157. loadDictData().then(() => {
  158. dynamicFormItems.value = [
  159. {
  160. label: 'APP应用',
  161. prop: 'appId',
  162. type: 'select',
  163. options: appListOptions.value,
  164. },
  165. ]
  166. })
  167. }
  168. const appListData = ref([])
  169. const appListOptions = ref([])
  170. const getEnabledListData = async () => {
  171. let res = await getEnabledList()
  172. // appListData.value = res.data
  173. appListOptions.value = res.data.map(item => ({
  174. label: item.appName,
  175. value: item.appId
  176. }))
  177. appListData.value = res.data.map(item => ({
  178. appName: item.appName,
  179. appId: item.appId
  180. }))
  181. dynamicFormItems.value = [
  182. {
  183. label: 'APP应用',
  184. prop: 'appId',
  185. type: 'select',
  186. options: appListOptions.value,
  187. },
  188. ]
  189. }
  190. // 分页数据
  191. const getList = async () => {
  192. let res = await riskConfigList({ ...formSearch.value });
  193. tableData.value = res.data;
  194. page.total = res.pageMeta.total;
  195. };
  196. const changeTableData = () => {
  197. formSearch.value.page = page.pageNum;
  198. formSearch.value.pageSizes = page.pageSize;
  199. formSearch.value.limit = page.pageSize;
  200. // 分页切换
  201. getList();
  202. };
  203. // 搜索
  204. const handleFormSubmitted = (formData) => {
  205. // console.log("接收到子组件传递的数据", formData);
  206. formSearch.value.page = 1;
  207. formSearch.value.pageSizes = 20;
  208. formSearch.value.total = page.total;
  209. formSearch.value.limit = 20;
  210. formSearch.value.appId = formData.appId
  211. getList();
  212. };
  213. // 表单重置
  214. const handleFormReset = () => {
  215. formSearch.value = {
  216. appId: '',// 渠道来源关联的应用ID
  217. available: null,//
  218. channelId: null,//
  219. configId: '',// 配置ID
  220. configList: null,// 风控配置列表
  221. configType: 0,// 配置类型 1-输入框 2-选择框 3-日期
  222. configVal: '',// 配置值
  223. createTime: '',//
  224. createUserId: '',//
  225. defaultParam: '',//
  226. fieldDesc: '',// 字段描述
  227. fieldName: '',// 字段名称
  228. limit: 20,// 当前页数量(查询量)
  229. multy: null, //是否多个
  230. updateParam: null,// 用户类型
  231. updateTime: null,// 用户类型
  232. updateUserId: null,// 用户类型
  233. page: 1,// 当前页码
  234. pageSizes: 20,// 总页数
  235. superAdmin: null,//
  236. total: null,// 总条数
  237. };
  238. getList();
  239. };
  240. // 选择监听器
  241. const handleSelectionChange = (val) => {
  242. context.emit("selection-change", val)
  243. }
  244. // #region 新增/编辑风控配置
  245. // 弹窗
  246. const layer = ref({
  247. show: false,
  248. title: "配置风控表单",
  249. showButton: true,
  250. width: '60%',
  251. height: '60vh',
  252. optionsData: [],
  253. configDataList: {},
  254. templateId: '',
  255. disabled: false
  256. });
  257. // 查询配置字段选项列表
  258. const riskOptionsData = ref([])
  259. const getRiskOptions = async () => {
  260. let res = await riskOptions({appIds: appListData.value.map(item=>item.appId).join(",")})
  261. riskOptionsData.value = res.data
  262. layer.value.optionsData = res.data
  263. }
  264. const edit = async (row) => {
  265. layer.value.show = true
  266. if (row) {
  267. layer.value.title = '编辑配置'
  268. layer.value.disabled = true
  269. layer.value.templateId = row.templateId
  270. } else {
  271. layer.value.title = '配置风控表单'
  272. layer.value.disabled = false
  273. }
  274. }
  275. const close = () => {
  276. layer.value.show = false
  277. }
  278. const submit = async (data, isEdit) => {
  279. data.channelId = store.state.user.info.userId //渠道id就是用户的userId
  280. data.configList.forEach((item, index) => {
  281. data.configList[index].configType = Number(item.configType)
  282. data.configList[index].configVal = String(item.configVal)
  283. data.configList[index].multy = Number(item.multy)
  284. })
  285. // 编辑
  286. if (isEdit) {
  287. let res = await riskUpdateConfig({ ...data })
  288. if (res.code === 200) {
  289. ElMessage.success('配置保存成功')
  290. getList();
  291. }
  292. } else {
  293. let res = await riskSaveConfig(
  294. {
  295. configList: data.configList,
  296. templateName: data.templateName,
  297. templateContent: data.templateContent,
  298. templateCode: data.templateCode,
  299. allSatisfy: data.allSatisfy,
  300. effectNode: data.effectNode
  301. })
  302. if (res.code === 200) {
  303. ElMessage.success('配置保存成功')
  304. getList();
  305. }
  306. }
  307. }
  308. // #endregion
  309. // #region 风控配置关联应用
  310. const layer1 = ref({
  311. show: false,
  312. title: "关联应用",
  313. showButton: true,
  314. width: 300,
  315. });
  316. const formEdit = ref({
  317. appList: {}, //appId list
  318. operator: '',//操作人
  319. operatorName: '',//操作人名称
  320. templateId: '', //关联的配置模版ID
  321. })
  322. const relativeApp = (row) => {
  323. ruleForm.value?.resetFields()
  324. layer1.value.show = true
  325. formEdit.value.operator = store.state.user.info.loginName
  326. formEdit.value.operatorName = store.state.user.info.nickName
  327. formEdit.value.templateId = row.templateId
  328. formEdit.value.appList = []
  329. }
  330. const ruleForm = ref(null);
  331. const rules = reactive({
  332. appList: [
  333. {
  334. required: true,
  335. message: "请选择应用",
  336. trigger: "change",
  337. },
  338. ],
  339. });
  340. const submit1 = async (formEl) => {
  341. const result = appListData.value.filter(app => formEdit.value.appList.includes(app.appId));
  342. // console.log('result', result)
  343. formEdit.value.appList = result
  344. await formEl.validate(async (valid, fields) => {
  345. if (valid) {
  346. // 提交内容
  347. riskRelativeApps(formEdit.value).then((res) => {
  348. ElMessage.success('关联应用成功')
  349. layer1.value.show = false;
  350. getList();
  351. })
  352. } else {
  353. console.log("error submit!", fields);
  354. }
  355. })
  356. }
  357. // #endregion
  358. // 启用或关闭配置
  359. const enabledConfig = async (row) => {
  360. let res = await riskEnabledConfig({ templateId: row.templateId })
  361. if (res.code == 200) {
  362. ElMessage.success('更改成功')
  363. getList();
  364. }
  365. }
  366. </script>
  367. <style scoped lang="scss">
  368. .layout-container {
  369. .card {
  370. .title {
  371. margin-bottom: 10px;
  372. font-weight: 600;
  373. }
  374. display: flex;
  375. flex-direction: column;
  376. align-items: start;
  377. width: calc(100% - 60px);
  378. margin: 30px 30px 0;
  379. }
  380. .button {
  381. display: flex;
  382. flex-direction: column;
  383. .button-item {
  384. margin: 4px;
  385. }
  386. }
  387. }
  388. </style>