riskLogsList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <template>
  2. <div class="layout-container">
  3. <!-- 菜单栏 -->
  4. <From :form-items="dynamicFormItems" @formSubmitted="handleFormSubmitted" @formReset="handleFormReset" />
  5. <!-- 表格 -->
  6. <div class="layout-container">
  7. <Table @getTableData="changeTableData" v-model:page="page" ref="table" :data="tableData"
  8. @selection-change="handleSelectionChange">
  9. <el-table-column prop="appId" label="应用ID" width="150" />
  10. <el-table-column prop="appName" label="应用名称" width="150" />
  11. <el-table-column prop="nickName" label="用户昵称" width="120" />
  12. <el-table-column prop="userId" label="用户ID" width="120" />
  13. <el-table-column prop="userStatus" label="用户状态" width="90">
  14. <template #default="scope">
  15. {{ getDictionaryName('user_status',scope.row.userStatus) }}
  16. </template>
  17. </el-table-column>
  18. <el-table-column prop="bannedLimit" label="风控期限(天)" width="130">
  19. <template #default="scope">
  20. {{ (scope.row.bannedLimit / 24) }}
  21. </template>
  22. </el-table-column>
  23. <el-table-column prop="bannedReason" label="封禁原因" width="260" />
  24. <el-table-column prop="bannedTime" label="封禁时间" width="160">
  25. <template #default="scope">
  26. {{ convertUTCToBeijing(scope.row.bannedTime) }}
  27. </template>
  28. </el-table-column>
  29. <el-table-column prop="bannedType" label="封禁类型" width="90">
  30. <template #default="scope">
  31. {{ scope.row.bannedType === 1 ? '渠道' : '平台' }}
  32. </template>
  33. </el-table-column>
  34. <el-table-column prop="channelId" label="渠道商ID" width="110" />
  35. <el-table-column prop="phoneModel" label="用户设备" width="160" >
  36. <template #default="scope">
  37. {{ scope.row.phoneBrand }} {{ scope.row.phoneModel }}
  38. </template>
  39. </el-table-column>
  40. <el-table-column prop="platformId" label="平台ID" width="150" />
  41. <el-table-column prop="communicationOperator" label="IP运营商" width="120" />
  42. <el-table-column prop="ipAddr" label="IP归属地" width="200" />
  43. <el-table-column prop="lastLoginIp" label="最新登录IP" width="150" />
  44. <el-table-column prop="lastLoginTime" label="最新登录时间" width="160">
  45. <template #default="scope">
  46. {{ convertUTCToBeijing(scope.row.lastLoginTime) }}
  47. </template>
  48. </el-table-column>
  49. <el-table-column prop="operatorName" label="操作人" width="90" />
  50. <el-table-column prop="registryTime" label="注册时间" width="160">
  51. <template #default="scope">
  52. {{ convertUTCToBeijing(scope.row.registryTime) }}
  53. </template>
  54. </el-table-column>
  55. <!-- <el-table-column label="操作" width="150" fixed="right">
  56. <template #default="scope">
  57. <div class="button">
  58. <el-tooltip
  59. :content="shareAppIds.includes(scope.row.appId) ? '您没有权限解封此应用下的用户' : '用户解封'"
  60. placement="top"
  61. >
  62. <el-button
  63. class="button-item"
  64. type="primary"
  65. style="margin-bottom: 5px;"
  66. @click="editUserType(scope.row)"
  67. :disabled="shareAppIds.includes(scope.row.appId)"
  68. >
  69. 解封
  70. </el-button>
  71. </el-tooltip>
  72. </div>
  73. </template>
  74. </el-table-column> -->
  75. </Table>
  76. </div>
  77. <!-- 操作弹窗 -->
  78. <Layer :layer="layer" @confirm="submit(ruleForm)" @close="layer.show = false">
  79. <el-form :model="formEdit" :rules="rules" ref="ruleForm" label-width="120px" style="margin-right:30px;">
  80. <el-form-item label="解封原因:" required prop="reason">
  81. <el-input v-model="formEdit.reason" placeholder="请输入封禁原因" clearable />
  82. </el-form-item>
  83. </el-form>
  84. </Layer>
  85. </div>
  86. </template>
  87. <script setup>
  88. import { onBeforeMount, ref, reactive } from "vue";
  89. import From from "@/components/from/index.vue";
  90. import Table from "@/components/table/index.vue";
  91. import Layer from '@/components/layer/index.vue'
  92. import Card from './components/card/index.vue'
  93. import { ElMessage } from 'element-plus'
  94. import { getUserList, getStaticList, riskBannedUser, riskLockUser } from '@/api/userModule.js'
  95. import { riskBannedList, riskChangeUserStatus } from '@/api/riskModule.js'
  96. import { convertUTCToBeijing } from '@/utils/index.js'
  97. import { ditchList } from '@/api/outBagModule.js'
  98. import { useGetDictList } from '@/hooks/useGetDictList.js'
  99. import { useStore } from 'vuex'
  100. const store = useStore()
  101. const { dictData, loadDictData, getOptions, getDictionaryName } = useGetDictList();
  102. const form = ref(null);
  103. const tableData = ref([]);
  104. // 用户分享的渠道AppiD
  105. //const shareAppIds = ref([]);
  106. // 分页参数, 供table使用
  107. const page = reactive({
  108. pageNum: 1,
  109. pageSize: 20,
  110. total: 0,
  111. });
  112. const formSearch = ref({
  113. userId: null,//用户ID
  114. appId: null,// 应用ID
  115. bannedReason: null, //封禁原因
  116. bannedTimeBegin: null, //封禁开始时间
  117. bannedTimeEnd: null, //封禁结束时间
  118. channelId: null,// 渠道商ID
  119. channelOrigin: null, //渠道来源
  120. channelType: null,//渠道类型
  121. limit: 20,// 当前页数量(查询量)
  122. page: 1,// 当前页码
  123. });
  124. const dynamicFormItems = ref([])
  125. onBeforeMount(() => {
  126. settingData()
  127. // getList();
  128. });
  129. // 获取缓存数据设置筛选数据
  130. const settingData = () => {
  131. loadDictData().then(async() => {
  132. dynamicFormItems.value = [
  133. {
  134. label: '用户ID',
  135. prop: 'userId',
  136. type: 'input',
  137. needEnterEvent: true
  138. },
  139. {
  140. label: '应用ID',
  141. prop: 'appId',
  142. type: 'input',
  143. needEnterEvent: true
  144. },
  145. {
  146. label: '封禁原因',
  147. prop: 'bannedReason',
  148. type: 'input',
  149. needEnterEvent: true
  150. },
  151. {
  152. label: '渠道来源',
  153. prop: 'channelOrigin',
  154. type: 'select',
  155. options: getOptions('channel_origin'),
  156. },
  157. { label: '封禁时间', prop: 'bannedTime', type: 'daterange' },
  158. ]
  159. await getApiOptions()
  160. })
  161. }
  162. // 渠道来源
  163. const getApiOptions = async () => {
  164. try {
  165. const { data: ditchData } = await ditchList({ page: 1, limit: 9999 })
  166. const ditchOptions = ditchData.map(item => ({
  167. label: item.ditchName,
  168. value: item.ditchId
  169. }))
  170. // 赋值到表单项
  171. dynamicFormItems.value[3].options = ditchOptions
  172. // const currentUserId = store.state.user.info.userId
  173. // ditchData.forEach(item => {
  174. // // 检查是否满足条件:sharedUserId 等于当前登录用户的 userId
  175. // if (item.sharedUserId === currentUserId) {
  176. // // 将符合条件的 appId 添加到 shareAppIds 数组中
  177. // shareAppIds.value.push(item.appId)
  178. // }
  179. // })
  180. // // 去重,避免重复添加相同的 appId
  181. // shareAppIds.value = [...new Set(shareAppIds.value)]
  182. // console.log("分享的appId",shareAppIds)
  183. // 获取列表数据
  184. getList()
  185. } catch (err) {
  186. console.error('获取选项失败:', err)
  187. }
  188. }
  189. // 分页数据
  190. const getList = async () => {
  191. let res = await riskBannedList({ ...formSearch.value });
  192. tableData.value = res.data;
  193. page.total = res.pageMeta.total;
  194. };
  195. const changeTableData = (type) => {
  196. formSearch.value.page = type ? 1 : page.pageNum;
  197. formSearch.value.limit = page.pageSize;
  198. // 分页切换
  199. getList();
  200. };
  201. // 搜索
  202. const handleFormSubmitted = (formData) => {
  203. // console.log("接收到子组件传递的数据", formData.appId);
  204. formSearch.value.page = page.pageNum;
  205. formSearch.value.limit = page.pageSize;
  206. formSearch.value.appId = formData.appId;
  207. formSearch.value.userId = formData.userId;
  208. formSearch.value.bannedReason = formData.bannedReason;
  209. formSearch.value.channelId = formData.channelId;
  210. formSearch.value.channelOrigin = formData.channelOrigin;
  211. formSearch.value.channelType = formData.channelType;
  212. // 封禁时间
  213. if (formData.bannedTime) {
  214. formSearch.value.bannedTimeBegin = convertUTCToBeijing(formData.bannedTime[0], false);
  215. formSearch.value.bannedTimeEnd = convertUTCToBeijing(formData.bannedTime[1], false);
  216. }else {
  217. formSearch.value.bannedTimeBegin = null
  218. formSearch.value.bannedTimeEnd = null
  219. }
  220. getList();
  221. };
  222. // 表单重置
  223. const handleFormReset = () => {
  224. formSearch.value = {
  225. userId: null,//用户ID
  226. appId: null,// 应用ID
  227. bannedReason: null, //封禁原因
  228. bannedTimeBegin: null, //封禁开始时间
  229. bannedTimeEnd: null, //封禁结束时间
  230. channelId: null,// 渠道商ID
  231. channelOrigin: null, //渠道来源
  232. channelType: null,//渠道类型
  233. limit: 20,// 当前页数量(查询量)
  234. page: 1,// 当前页码
  235. };
  236. page.pageNum = 1
  237. page.pageSize = 20
  238. page.total = 0
  239. getList();
  240. };
  241. // 选择监听器
  242. const handleSelectionChange = (val) => {
  243. context.emit("selection-change", val)
  244. }
  245. // 弹窗
  246. const layer = ref({
  247. show: false,
  248. title: "解封用户",
  249. showButton: true,
  250. width: '300px'
  251. })
  252. const formEdit = ref({
  253. bannedType: '',//封禁类型 1-渠道 2-平台
  254. operator: '',//操作人
  255. operatorName: '',//操作人名称
  256. reason: '',//封禁原因
  257. userId: '', //用户ID
  258. userStatus: '', //用户状态
  259. })
  260. const editUserType = (row) => {
  261. // 检查权限
  262. // if (shareAppIds.value.includes(row.appId)) {
  263. // ElMessage.warning('您没有权限解封此应用下的用户')
  264. // return
  265. // }
  266. ruleForm.value?.resetFields()
  267. layer.value.show = true
  268. layer.value.title = `解封用户${row.nickName}`
  269. formEdit.value.bannedType = row.channelType
  270. formEdit.value.operator = store.state.user.info.loginName
  271. formEdit.value.operatorName = store.state.user.info.nickName
  272. formEdit.value.userId = row.userId
  273. formEdit.value.userStatus = 1 //正常
  274. }
  275. const ruleForm = ref(null);
  276. const rules = reactive({
  277. reason: [
  278. {
  279. required: true,
  280. message: "请输入解封原因",
  281. trigger: ["blur"],
  282. },
  283. ],
  284. });
  285. const submit = async (formEl) => {
  286. await formEl.validate(async (valid, fields) => {
  287. if (valid) {
  288. // 提交内容
  289. riskChangeUserStatus({ ...formEdit.value }).then((res) => {
  290. ElMessage.success('用户解封成功')
  291. getList();
  292. })
  293. } else {
  294. console.log("error submit!", fields);
  295. }
  296. })
  297. layer.value.show = false
  298. }
  299. </script>
  300. <style scoped lang="scss">
  301. .layout-container {
  302. .card {
  303. .title {
  304. margin-bottom: 10px;
  305. font-weight: 600;
  306. }
  307. display: flex;
  308. flex-direction: column;
  309. align-items: start;
  310. width: calc(100% - 60px);
  311. margin: 30px 30px 0;
  312. }
  313. .button {
  314. display: flex;
  315. flex-direction: column;
  316. .button-item {
  317. margin: 4px;
  318. }
  319. }
  320. }
  321. </style>