deepchart后台管理系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1734 lines
47 KiB

4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
  1. <template>
  2. <div>
  3. <div class="page-container" v-show="taber == 'DeepMate'">
  4. <!-- 搜索区域 -->
  5. <div class="search-container" @keyup.enter="searchDM">
  6. <div class="search-form">
  7. <div class="search-group">
  8. <div class="search-group1">
  9. <div class="search-item">
  10. <span class="form-label">账号</span>
  11. <el-input
  12. v-model="searchFormDM.dccode"
  13. placeholder="请输入账号"
  14. clearable
  15. style="height: 36px; width: 140px;"
  16. />
  17. </div>
  18. <div class="search-item">
  19. <span class="form-label">姓名</span>
  20. <el-input
  21. v-model="searchFormDM.dcname"
  22. placeholder="请输入姓名"
  23. clearable
  24. style="height: 36px; width: 180px;"
  25. />
  26. </div>
  27. <div class="search-item">
  28. <span class="form-label">归属</span>
  29. <el-input
  30. v-model="searchFormDM.inviter"
  31. placeholder="请输入归属账号"
  32. clearable
  33. style="height: 36px; width: 140px;"
  34. />
  35. </div>
  36. </div>
  37. <div class="search-group2">
  38. <!-- <div class="search-item">
  39. <span class="form-label">是否登录过</span>
  40. <el-select
  41. v-model="searchFormDM.is_login"
  42. placeholder="请选择是否登录过"
  43. clearable
  44. style="height: 36px; width: 140px;"
  45. >
  46. <el-option label="登录过" value="1" />
  47. <el-option label="未登录过" value="0" />
  48. </el-select>
  49. </div> -->
  50. <div class="search-item">
  51. <span class="form-label">客户类型</span>
  52. <el-select
  53. v-model="searchFormDM.user_role"
  54. placeholder="请选择客户类型"
  55. clearable
  56. style="height: 36px; width: 160px;"
  57. >
  58. <el-option label="非网" value="2" />
  59. <el-option label="会员" value="1" />
  60. </el-select>
  61. </div>
  62. <div class="search-item">
  63. <span class="form-label">地区</span>
  64. <el-select
  65. v-model="searchFormDM.market"
  66. placeholder="请选择地区"
  67. clearable
  68. filterable
  69. style="height: 36px; width: 160px;"
  70. :loading="isRegionLoading"
  71. >
  72. <el-option
  73. v-for="region in regionList"
  74. :key="region.ID"
  75. :label="region.Name"
  76. :value="region.ID"
  77. />
  78. </el-select>
  79. </div>
  80. </div>
  81. </div>
  82. <div class="button-group">
  83. <el-button type="primary" @click="searchDM">搜索</el-button>
  84. <el-button type="danger" @click="enableAccessDM">开通权限</el-button>
  85. <el-button type="success" @click="exportExcelDM">导出Excel列表</el-button>
  86. <el-button color="#626aef" @click="exportListDM">查看导出列表</el-button>
  87. <el-button type="primary" @click="resetBnDM">重置</el-button>
  88. </div>
  89. </div>
  90. </div>
  91. <!-- tab切换 -->
  92. <div class="tab-group">
  93. <button
  94. class="tab-btn"
  95. :class="{ active: taber === 'DeepMate' }"
  96. @click="taber = 'DeepMate'"
  97. >
  98. DeepMate
  99. </button>
  100. <button
  101. class="tab-btn"
  102. :class="{ active: taber === 'DeepExplore' }"
  103. @click="taber = 'DeepExplore'"
  104. >
  105. 深度探索
  106. </button>
  107. </div>
  108. <!-- 数据 -->
  109. <el-table
  110. :data="tableDataDM"
  111. style="width: 100%; margin-top: 20px;"
  112. header-cell-class-name="table-header"
  113. @sort-change="handleSortChangeDM"
  114. :default-sort="{ order: null }"
  115. class="table-rounded"
  116. :loading="tableLoadingDM"
  117. >
  118. <el-table-column prop="id" label="序号" align="center" header-align="center" width="80">
  119. <template #default="scope">
  120. {{ (currentPageDM - 1) * pageSizeDM + scope.$index + 1 }}
  121. </template>
  122. </el-table-column>
  123. <el-table-column prop="dccode" label="账号" align="center" header-align="center"/>
  124. <el-table-column prop="dcname" label="姓名" align="center" header-align="center"/>
  125. <el-table-column prop="inviter" label="归属" align="center" header-align="center"/>
  126. <!-- <el-table-column prop="is_login" label="是否登录" align="center" header-align="center">
  127. <template #default="scope">
  128. <el-tag
  129. v-if="scope.row.is_login === 1"
  130. :key="1"
  131. type="success"
  132. effect="light"
  133. >
  134. 登录过
  135. </el-tag>
  136. <el-tag
  137. v-else
  138. :key="2"
  139. type="error"
  140. effect="light"
  141. >
  142. 没登录过
  143. </el-tag>
  144. </template>
  145. </el-table-column> -->
  146. <el-table-column prop="module_name" label="模块名称" align="center" header-align="center"/>
  147. <el-table-column prop="remain_num" label="token数量" align="center" header-align="center"/>
  148. <el-table-column prop="remain_free_num" label="免费token" align="center" header-align="center"/>
  149. <el-table-column prop="remain_pay_num" label="付费token" align="center" header-align="center"/>
  150. <el-table-column prop="updated_at" label="操作时间" align="center" header-align="center" sortable="custom"/>
  151. <el-table-column label="操作" align="center" header-align="center">
  152. <template #default="scope">
  153. <el-button type="text" @click="handleEditDM(scope.row)">编辑</el-button>
  154. <el-button type="text" @click="handleLogDM(scope.row.dccode)">操作日志</el-button>
  155. </template>
  156. </el-table-column>
  157. </el-table>
  158. <!-- 分页组件 -->
  159. <div class="demo-pagination-block">
  160. <el-pagination
  161. @size-change="handleSizeChangeDM"
  162. @current-change="handleCurrentChangeDM"
  163. :current-page="currentPageDM"
  164. :page-sizes="[10, 20, 50, 100]"
  165. :page-size="pageSizeDM"
  166. layout="total, sizes, prev, pager, next, jumper"
  167. :total= "datatotalDM"
  168. />
  169. </div>
  170. <!-- 开通/编辑弹窗 -->
  171. <el-dialog v-model="dialogVisibleDM" :title="addOrUpdataDM === 1 ? '添加权限' : '修改'" width="500px" :before-close="cancelDM">
  172. <!-- 设置用户 -->
  173. <div class="form-item" v-if="addOrUpdataDM === 1">
  174. <label class="form-label">设置用户</label>
  175. <el-input type="textarea" v-model="hlidsInput" rows=10
  176. placeholder="请输入HLid...
  177. 示例
  178. 90048004
  179. 90048005
  180. 90048006"
  181. />
  182. <div class="tip">支持批量输入每次最多1000个手动/Excel粘贴均可</div>
  183. </div>
  184. <!-- 编辑回显 -->
  185. <div class="info-container" v-if="addOrUpdataDM === 0">
  186. <span class="info-item">HLid: {{ hlidsInput }}</span>
  187. <span class="info-item">剩余次数{{ deadtoken }}</span>
  188. </div>
  189. <!-- 设置数量 -->
  190. <div class="form-item" v-if="addOrUpdataDM === 1">
  191. <label class="form-label">设置用户次数</label>
  192. <div class="count-group">
  193. <!-- Deep Mate不可编辑文本框 -->
  194. <el-input v-model="dmText" disabled style="width: 120px; margin-right: 16px;"/>
  195. <!-- token类型下拉框 -->
  196. <el-select v-model="token_type" style="width: 100px; margin-right: 16px;">
  197. <el-option label="免费token" value="free_num" />
  198. <el-option label="付费token" value="pay_num" />
  199. </el-select>
  200. <!-- token数量只能正整数 -->
  201. <el-input v-model.number="token_num" type="number" style="width: 140px;" placeholder="请输入次数(只能为正)"/>
  202. </div>
  203. </div>
  204. <div class="form-item" v-if="addOrUpdataDM === 0">
  205. <label class="form-label">修改用户次数</label>
  206. <div class="count-group">
  207. <!-- Deep Mate不可编辑文本框 -->
  208. <el-input v-model="dmText" disabled style="width: 160px; margin-right: 16px;"/>
  209. <!-- token类型下拉框 -->
  210. <!-- <el-select v-model="token_type" style="width: 140px; margin-right: 16px;">
  211. <el-option label="免费token" value="free_num" />
  212. <el-option label="付费token" value="pay_num" />
  213. </el-select> -->
  214. <!-- token数量支持正负整数 -->
  215. <el-input v-model.number="token_num" type="number" style="width: 140px;" placeholder="请输入次数(可正负)"/>
  216. </div>
  217. </div>
  218. <!-- 备注-->
  219. <div class="form-item inline-form-item">
  220. <label class="form-label">备注</label>
  221. <el-input
  222. type="textarea"
  223. v-model="remark"
  224. rows=3
  225. placeholder="请输入备注..."
  226. maxlength="150"
  227. show-word-limit
  228. />
  229. </div>
  230. <!-- 操作人 -->
  231. <div class="form-item inline-form-item">
  232. <label class="form-label">操作人</label>
  233. <el-input v-model="operator" placeholder="请填写操作人"/>
  234. </div>
  235. <!-- 按钮区域 -->
  236. <div class="dialog-footer">
  237. <el-button type="default" plain @click="cancelDM">取消</el-button>
  238. <el-button type="primary" @click="submitFormDM" style="background-color: #ff0000; border-color: #ff0000;">提交</el-button>
  239. </div>
  240. </el-dialog>
  241. </div>
  242. <div class="page-container" v-show="taber == 'DeepExplore'">
  243. <!-- 搜索区域 -->
  244. <div class="search-containerDE" @keyup.enter="searchDE">
  245. <!-- 输入项区域 -->
  246. <div class="search-formDE">
  247. <div class="search-groupDE">
  248. <div class="search-groupDE1">
  249. <div class="search-itemDE">
  250. <span class="form-labelDE">账号</span>
  251. <el-input
  252. v-model="searchFormDE.dccode"
  253. placeholder="请输入账号"
  254. clearable
  255. style="height: 36px; width: 140px;"
  256. />
  257. </div>
  258. <div class="search-itemDE">
  259. <span class="form-labelDE">姓名</span>
  260. <el-input
  261. v-model="searchFormDE.dcname"
  262. placeholder="请输入姓名"
  263. clearable
  264. style="height: 36px; width: 180px;"
  265. />
  266. </div>
  267. <div class="search-itemDE">
  268. <span class="form-labelDE">归属</span>
  269. <el-input
  270. v-model="searchFormDE.inviter"
  271. placeholder="请输入归属账号"
  272. clearable
  273. style="height: 36px; width: 180px;"
  274. />
  275. </div>
  276. </div>
  277. <div class="search-groupDE2">
  278. <!-- <div class="search-itemDE">
  279. <span class="form-labelDE">是否登录过</span>
  280. <el-select
  281. v-model="searchFormDE.is_login"
  282. placeholder="请选择是否登录过"
  283. clearable
  284. style="height: 36px; width: 140px;"
  285. >
  286. <el-option label="登录过" value="1" />
  287. <el-option label="未登录过" value="0" />
  288. </el-select>
  289. </div> -->
  290. <div class="search-itemDE">
  291. <span class="form-labelDE">客户类型</span>
  292. <el-select
  293. v-model="searchFormDE.user_role"
  294. placeholder="请选择客户类型"
  295. clearable
  296. style="height: 36px; width: 160px;"
  297. >
  298. <el-option label="非网" value="2" />
  299. <el-option label="会员" value="1" />
  300. </el-select>
  301. </div>
  302. <div class="search-itemDE">
  303. <span class="form-labelDE">地区</span>
  304. <el-select
  305. v-model="searchFormDE.market"
  306. placeholder="请选择地区"
  307. clearable
  308. filterable
  309. style="height: 36px; width: 160px;"
  310. :loading="isRegionLoading"
  311. >
  312. <el-option
  313. v-for="region in regionList"
  314. :key="region.ID"
  315. :label="region.Name"
  316. :value="region.ID"
  317. />
  318. </el-select>
  319. </div>
  320. <div class="search-itemDE">
  321. <span class="form-labelDE">指标名称</span>
  322. <el-select
  323. v-model="searchFormDE.indicator_id"
  324. placeholder="请选择指标名称"
  325. clearable
  326. style="height: 36px; width: 160px;"
  327. >
  328. <el-option
  329. v-for="item in indicatorOptions"
  330. :key="item.id"
  331. :label="item.name"
  332. :value="item.id"
  333. />
  334. </el-select>
  335. </div>
  336. </div>
  337. </div>
  338. <!-- 按钮组 -->
  339. <div class="button-groupDE">
  340. <el-button type="primary" @click="searchDE">搜索</el-button>
  341. <el-button type="danger" @click="enableAccessDE">开通权限</el-button>
  342. <el-button type="success" @click="exportExcelDE">导出Excel列表</el-button>
  343. <el-button color="#626aef" @click="exportListDE">查看导出列表</el-button>
  344. <el-button type="primary" @click="resetBnDE">重置</el-button>
  345. </div>
  346. </div>
  347. </div>
  348. <!-- tab切换 -->
  349. <div class="tab-group">
  350. <button
  351. class="tab-btn"
  352. :class="{ active: taber === 'DeepMate' }"
  353. @click="taber = 'DeepMate'"
  354. >
  355. DeepMate
  356. </button>
  357. <button
  358. class="tab-btn"
  359. :class="{ active: taber === 'DeepExplore' }"
  360. @click="taber = 'DeepExplore'"
  361. >
  362. 深度探索
  363. </button>
  364. </div>
  365. <!-- 数据 -->
  366. <el-table
  367. :data="tableDataDE"
  368. style="width: 100%; margin-top: 20px;"
  369. header-cell-class-name="table-header"
  370. @sort-change="handleSortChangeDE"
  371. :default-sort="{ prop: null, order: null }"
  372. class="table-roundedDE"
  373. :loading="tableLoadingDE"
  374. >
  375. <el-table-column prop="id" label="序号" align="center" header-align="center" width="80">
  376. <template #default="scope">
  377. {{ (currentPageDE - 1) * pageSizeDE + scope.$index + 1 }}
  378. </template>
  379. </el-table-column>
  380. <el-table-column prop="dccode" label="账号" align="center" header-align="center"/>
  381. <el-table-column prop="dcname" label="姓名" align="center" header-align="center"/>
  382. <el-table-column prop="inviter" label="归属" align="center" header-align="center"/>
  383. <!-- <el-table-column prop="is_login" label="是否登录" align="center" header-align="center">
  384. <template #default="scope">
  385. <el-tag
  386. v-if="scope.row.is_login === 1"
  387. :key="1"
  388. type="success"
  389. effect="light"
  390. >
  391. 登录过
  392. </el-tag>
  393. <el-tag
  394. v-else
  395. :key="2"
  396. type="error"
  397. effect="light"
  398. >
  399. 没登录过
  400. </el-tag>
  401. </template>
  402. </el-table-column> -->
  403. <el-table-column prop="name" label="指标名称" align="center" header-align="center" width="200">
  404. <template #default="scope">
  405. <el-tooltip
  406. effect="dark"
  407. :content="scope.row.name"
  408. placement="top"
  409. >
  410. <span class="ellipsis-text">{{ scope.row.name }}</span>
  411. </el-tooltip>
  412. </template>
  413. </el-table-column>
  414. <el-table-column prop="created_at" label="开通时间" align="center" header-align="center" sortable="custom" width="200"/>
  415. <el-table-column prop="expire_time" label="到期时间" align="center" header-align="center" sortable="custom" width="200"/>
  416. <el-table-column label="操作" align="center" header-align="center" width="200">
  417. <template #default="scope">
  418. <el-button type="text" @click="handleEditDE(scope.row)">编辑</el-button>
  419. <el-button type="text" @click="handleDetailsDE(scope.row.dccode)">权限详情</el-button>
  420. <el-button type="text" @click="handleLogDE(scope.row.dccode)">操作日志</el-button>
  421. </template>
  422. </el-table-column>
  423. </el-table>
  424. <!-- 分页组件 -->
  425. <div class="demo-pagination-block">
  426. <el-pagination
  427. @size-change="handleSizeChangeDE"
  428. @current-change="handleCurrentChangeDE"
  429. :current-page="currentPageDE"
  430. :page-sizes="[10, 20, 50, 100]"
  431. :page-size="pageSizeDE"
  432. layout="total, sizes, prev, pager, next, jumper"
  433. :total= "datatotalDE"
  434. />
  435. </div>
  436. <!-- 开通/编辑 -->
  437. <el-dialog v-model="dialogVisibleDE" :title="addOrUpdataDE === 1 ? '添加权限' : '设置'" width="550px" :before-close="cancelDE">
  438. <!-- 设置用户 -->
  439. <div class="form-item" v-if="addOrUpdataDE === 1">
  440. <label class="form-label">设置用户</label>
  441. <el-input type="textarea" v-model="hlidsInputDE" rows=10
  442. placeholder="请输入HLid...
  443. 示例
  444. 90048004
  445. 90048005
  446. 90048006"
  447. />
  448. <div class="tip">支持批量输入每次最多1000个手动/Excel粘贴均可</div>
  449. </div>
  450. <!-- 编辑回显 -->
  451. <div class="info-container" v-if="addOrUpdataDE === 0">
  452. <span class="info-item">Homily ID{{ hlidsInputDE }}</span>
  453. <span class="info-item">当前到期时间{{ deadline.split(' ')[0] }}</span>
  454. </div>
  455. <!-- 设置指标 -->
  456. <div class="form-item">
  457. <label class="form-label">选择模板</label>
  458. <el-checkbox-group v-model="indicator_id" class="indicator-checkbox-group">
  459. <el-checkbox
  460. v-for="item in indicatorOptions"
  461. :key="item.id"
  462. :label="item.id"
  463. class="indicator-checkbox-item"
  464. >
  465. {{ item.name }}
  466. </el-checkbox>
  467. </el-checkbox-group>
  468. </div>
  469. <!-- 设置权限时间 -->
  470. <div class="form-item">
  471. <label class="form-label">设置权限时间</label>
  472. <el-radio-group v-model="timeType" class="radio-group">
  473. <el-radio label="expire" class="radio-item">
  474. <span>到期时间</span>
  475. <el-date-picker
  476. v-model="expireTime"
  477. type="date"
  478. placeholder="请选择到期日期"
  479. :disabled-date="disabledDate"
  480. style="width: 220px; margin-left: 8px;"
  481. />
  482. </el-radio>
  483. <el-radio label="delay" class="radio-item">
  484. <span>延期时间</span>
  485. <el-input
  486. v-model.number="delayValue"
  487. type="number"
  488. style="width: 60px; margin: 0 8px;"
  489. placeholder="1"
  490. @input="handleDelayInput"
  491. />
  492. <el-select v-model="delayUnit" placeholder="请选择" style="width: 150px;">
  493. <el-option label="年" value="year"></el-option>
  494. <el-option label="月" value="month"></el-option>
  495. <el-option label="周" value="week"></el-option>
  496. <el-option label="日" value="day"></el-option>
  497. </el-select>
  498. </el-radio>
  499. </el-radio-group>
  500. </div>
  501. <!-- 备注-->
  502. <div class="form-item inline-form-item">
  503. <label class="form-label">备注</label>
  504. <el-input
  505. type="textarea"
  506. v-model="remark"
  507. rows=3
  508. placeholder="请输入备注..."
  509. maxlength="150"
  510. show-word-limit
  511. />
  512. </div>
  513. <!-- 操作人 -->
  514. <div class="form-item inline-form-item">
  515. <label class="form-label">操作人</label>
  516. <el-input v-model="operator" placeholder="请填写操作人"/>
  517. </div>
  518. <!-- 按钮区域 -->
  519. <div class="dialog-footer">
  520. <el-button type="default" plain @click="cancelDE">取消</el-button>
  521. <el-button type="primary" @click="submitFormDE" style="background-color: #ff0000; border-color: #ff0000;">提交</el-button>
  522. </div>
  523. </el-dialog>
  524. <!-- 权限详情 -->
  525. <el-dialog
  526. v-model="showPermissionDetail"
  527. title="权限详情"
  528. width="400px"
  529. :close-on-click-modal="false"
  530. :show-close="true"
  531. class="permission-detail-dialog"
  532. >
  533. <div class="detail-container">
  534. <!-- HLid 信息 -->
  535. <div class="hlid-item">
  536. <span class="label">Homily ID</span>
  537. <span class="value">{{ HLid }}</span>
  538. </div>
  539. <!-- 到期时间区域 -->
  540. <div class="expire-section">
  541. <h3 class="section-title">到期时间</h3>
  542. <div class="indicator-list">
  543. <div
  544. v-for="(item, index) in permissionData"
  545. :key="index"
  546. class="indicator-item"
  547. >
  548. <span class="indicator-name">{{ item.name }}</span>
  549. <template v-if="item.is_expired === 1">
  550. <span class="expired-tag">已到期</span>
  551. </template>
  552. <template v-else>
  553. <span class="expire-time">{{ item.expire_time.split(' ')[0] }}</span>
  554. </template>
  555. </div>
  556. </div>
  557. </div>
  558. </div>
  559. </el-dialog>
  560. </div>
  561. </div>
  562. </template>
  563. <script setup>
  564. import { ref, reactive, onMounted, computed } from 'vue';
  565. import { ElMessage } from 'element-plus';
  566. import { marketListApi, indicatorListApi, userDMListApi, exportDeepMateApi, exitDMApi, userDEListApi, exportDeepExploreApi, exitDEApi, detailDEApi } from '../../api/userPermissions'
  567. import router from '../../router';
  568. import { useRoute } from 'vue-router';
  569. // token
  570. const token = localStorage.getItem('token')
  571. // tab切换
  572. const taber = ref('DeepMate')
  573. // 获取路由实例
  574. const route = useRoute();
  575. // 组件挂载时:获取地区列表 + 初始化表格数据
  576. onMounted(() => {
  577. const taberQuery = route.query.taber;
  578. const TaberValues = ["DeepMate", "DeepExplore"];
  579. taber.value = TaberValues.includes(String(taberQuery)) ? String(taberQuery) : "DeepMate";
  580. fetchRegionList();
  581. indicatorList();
  582. DMTableData();
  583. DETableData();
  584. });
  585. // 地区下拉框
  586. const regionList = ref([]);
  587. const isRegionLoading = ref(false);
  588. // 获取地区列表
  589. const fetchRegionList = async () => {
  590. try {
  591. isRegionLoading.value = true;
  592. const data = await marketListApi({
  593. token: token,
  594. app_form: "en"
  595. });
  596. regionList.value = data.list;
  597. } catch (error) {
  598. console.error('获取地区列表失败:', error);
  599. regionList.value = [];
  600. } finally {
  601. isRegionLoading.value = false;
  602. }
  603. };
  604. // DeepMate搜索表单
  605. const searchFormDM = reactive({
  606. dccode: '',
  607. dcname: '',
  608. is_login:'',
  609. inviter:'',
  610. market: '',
  611. user_role: ''
  612. });
  613. // DeepMate排序参数
  614. const sortOrderDM = ref(null);
  615. // DeepMate表格数据
  616. const tableDataDM = ref([]);
  617. const tableLoadingDM = ref(false);
  618. const datatotalDM = ref(0)
  619. // DeepMate分页参数
  620. const currentPageDM = ref(1);
  621. const pageSizeDM = ref(10);
  622. // DeepMate获取表格数据
  623. const DMTableData = async () => {
  624. try {
  625. tableLoadingDM.value = true;
  626. const requestParams = {
  627. token: token,
  628. dccode: searchFormDM.dccode,
  629. dcname: searchFormDM.dcname,
  630. is_login: searchFormDM.is_login,
  631. inviter: searchFormDM.inviter,
  632. market: searchFormDM.market,
  633. user_role: searchFormDM.user_role,
  634. sort_order: sortOrderDM.value,
  635. page: currentPageDM.value,
  636. page_size: pageSizeDM.value
  637. };
  638. const data = await userDMListApi(requestParams);
  639. tableDataDM.value = data.list
  640. datatotalDM.value = data.total
  641. } catch (error) {
  642. console.error('获取表格数据失败:', error);
  643. tableDataDM.value = [];
  644. datatotalDM.value = 0
  645. } finally {
  646. tableLoadingDM.value = false;
  647. }
  648. };
  649. // DeepMate分页方法
  650. const handleSizeChangeDM = (val) => {
  651. pageSizeDM.value = val;
  652. DMTableData();
  653. console.log(`每页 ${val}`);
  654. };
  655. const handleCurrentChangeDM = (val) => {
  656. currentPageDM.value = val;
  657. DMTableData();
  658. console.log(`当前页: ${val}`);
  659. };
  660. // DeepMate排序事件
  661. const handleSortChangeDM = (sort) => {
  662. const { order } = sort;
  663. sortOrderDM.value = order; // 保存当前排序方式
  664. DMTableData();
  665. };
  666. // DeepMate搜索按钮
  667. const searchDM = () => {
  668. currentPageDM.value = 1;
  669. DMTableData();
  670. };
  671. // DeepMate重置按钮
  672. const resetBnDM = () => {
  673. searchFormDM.dccode = '';
  674. searchFormDM.dcname = '';
  675. searchFormDM.is_login = '';
  676. searchFormDM.inviter = '';
  677. searchFormDM.market = '';
  678. searchFormDM.user_role = '';
  679. sortOrderDM.value = null;
  680. currentPageDM.value = 1;
  681. pageSizeDM.value = 10;
  682. DMTableData();
  683. };
  684. // DeepMate开通权限按钮
  685. const enableAccessDM = () => {
  686. dialogVisibleDM.value = true;
  687. addOrUpdataDM.value = 1;
  688. };
  689. // DeepMate导出Excel列表按钮
  690. const exportExcelDM = async () => {
  691. const requestParams = {
  692. token: token,
  693. dccode: searchFormDM.dccode,
  694. dcname: searchFormDM.dcname,
  695. is_login: searchFormDM.is_login,
  696. inviter: searchFormDM.inviter,
  697. market: searchFormDM.market,
  698. user_role: searchFormDM.user_role,
  699. sort_order: sortOrderDM.value
  700. };
  701. const data = await exportDeepMateApi(requestParams);
  702. if (data != '') {
  703. ElMessage.success('已导出');
  704. }
  705. };
  706. // DeepMate查看导出列表按钮
  707. const exportListDM = () => {
  708. router.push({
  709. path: "/userPermissions/export"
  710. });
  711. };
  712. // DeepMate编辑按钮
  713. const handleEditDM = (row) => {
  714. dialogVisibleDM.value = true;
  715. hlidsInput.value = row.dccode;
  716. deadtoken.value = row.token_num;
  717. };
  718. // DeepMate操作日志按钮
  719. const handleLogDM = (dccode) => {
  720. router.push({
  721. path: "/userPermissions/logDeepMate",
  722. query: { dccode: dccode }
  723. });
  724. };
  725. // DeepMate弹框显隐控制
  726. const dialogVisibleDM = ref(false);
  727. // DeepMate开通权限表单
  728. const hlidsInput = ref('');
  729. const dmText = ref('Deep Mate');
  730. const token_num = ref('');
  731. const token_type = ref('free_num'); // token类型:free_num-免费token, pay_num-付费token
  732. // DeepMate编辑回显内容
  733. const deadtoken = ref('');
  734. // DeepMate判断开通还是编辑
  735. const addOrUpdataDM = ref(0);
  736. // 校验HLid
  737. const checkHlids = () => {
  738. // 非空
  739. if (!hlidsInput.value.trim()) {
  740. ElMessage.error('请输入HLid');
  741. return false;
  742. }
  743. // 处理输入:去空、去重,转数组
  744. const hlidList = hlidsInput.value.split('\n')
  745. .map(item => item.trim())
  746. .filter(item => item)
  747. .filter((item, index, self) => self.indexOf(item) === index); // 去重
  748. // 数量校验(最多1000个)
  749. if (hlidList.length > 1000) {
  750. ElMessage.error('HLid数量不能超过1000个');
  751. return false;
  752. }
  753. // 格式校验(8位数字)
  754. const hlidReg = /^\d{8}$/;
  755. for (const hlid of hlidList) {
  756. if (!hlidReg.test(hlid)) {
  757. ElMessage.error(`有HLid格式错误:${hlid},请重新输入`);
  758. return false;
  759. }
  760. }
  761. return true;
  762. };
  763. // 校验token数量
  764. const checkTokenNum = () => {
  765. // 添加权限场景
  766. if (addOrUpdataDM.value === 1) {
  767. if (token_num.value === null || token_num.value === '') {
  768. ElMessage.error('请输入token数量');
  769. return false;
  770. }
  771. if (!Number.isInteger(token_num.value) || token_num.value <= 0) {
  772. ElMessage.error('token数量必须为正整数');
  773. return false;
  774. }
  775. }
  776. // 修改场景
  777. else if (addOrUpdataDM.value === 0) {
  778. if (token_num.value === null || token_num.value === '') {
  779. ElMessage.error('请输入token数量');
  780. return false;
  781. }
  782. if (!Number.isInteger(token_num.value)) {
  783. ElMessage.error('token数量必须为整数');
  784. return false;
  785. }
  786. if (token_num.value < 0 && Math.abs(token_num.value) > deadtoken.value) {
  787. ElMessage.error('扣除次数大于当前总次数,请重新输入次数');
  788. return false;
  789. }
  790. }
  791. return true;
  792. };
  793. // 防抖
  794. const NoshakeDM = ref(false)
  795. // DeepMate提交表单
  796. const submitFormDM = async () => {
  797. // 防抖
  798. if (NoshakeDM.value) return;
  799. NoshakeDM.value = true;
  800. // 表单校验
  801. if (!checkHlids() || !checkTokenNum() || !checkRemark()) {
  802. NoshakeDM.value = false;
  803. return;
  804. }
  805. try {
  806. const requestParams = {
  807. token: token,
  808. // HLid
  809. hlids: hlidsInput.value.split('\n')
  810. .map(item => item.trim())
  811. .filter(item => item)
  812. .join('\n'),
  813. // token数量根据类型分别传递
  814. ...(token_type.value === 'free_num'
  815. ? { free_num: token_num.value }
  816. : { pay_num: token_num.value }),
  817. // 备注
  818. remark: remark.value.trim(),
  819. // 操作人
  820. ...(operator.value.trim() && { operator: operator.value.trim() }),
  821. };
  822. console.log('传给后端的参数:', requestParams);
  823. // 调用后端接口
  824. await exitDMApi(requestParams);
  825. ElMessage.success(addOrUpdataDM.value === 1 ? '用户次数设置成功' : '用户次数修改成功');
  826. // 重置表单并关闭弹框
  827. resetFormDM();
  828. dialogVisibleDM.value = false;
  829. addOrUpdataDM.value = 0;
  830. // 重新获取表格
  831. DMTableData();
  832. } catch (error) {
  833. ElMessage.error('添加权限失败,请重试');
  834. } finally {
  835. NoshakeDM.value = false;
  836. }
  837. };
  838. // DeepMate取消表单
  839. const cancelDM = () => {
  840. resetFormDM();
  841. dialogVisibleDM.value = false;
  842. addOrUpdataDM.value = 0;
  843. };
  844. // DeepMate重置表单数据
  845. const resetFormDM = () => {
  846. hlidsInput.value = '';
  847. token_num.value = '';
  848. token_type.value = 'free_num';
  849. remark.value = '';
  850. operator.value = '';
  851. };
  852. // 深度探索指标选项
  853. const indicatorOptions = ref([]);
  854. const indicatorList = async () => {
  855. try {
  856. const data = await indicatorListApi({token: token});
  857. indicatorOptions.value = data.list;
  858. } catch (error) {
  859. console.error('获取指标列表失败:', error);
  860. indicatorOptions.value = [];
  861. }
  862. }
  863. // 深度探索搜索表单
  864. const searchFormDE = reactive({
  865. dccode: '',
  866. dcname: '',
  867. is_login:'',
  868. inviter: '',
  869. market: '',
  870. user_role: '',
  871. indicator_id: ''
  872. });
  873. // 深度探索排序参数
  874. const sortPropDE = ref(null);
  875. const sortOrderDE = ref(null);
  876. // 深度探索分页参数
  877. const currentPageDE = ref(1);
  878. const pageSizeDE = ref(10);
  879. // 深度探索表格数据
  880. const tableDataDE = ref([]);
  881. const tableLoadingDE = ref(false);
  882. const datatotalDE = ref(0)
  883. // 深度探索分页方法
  884. const handleSizeChangeDE = (val) => {
  885. pageSizeDE.value = val;
  886. DETableData();
  887. console.log(`每页 ${val}`);
  888. };
  889. const handleCurrentChangeDE = (val) => {
  890. currentPageDE.value = val;
  891. DETableData();
  892. console.log(`当前页: ${val}`);
  893. };
  894. // 深度探索排序事件
  895. const handleSortChangeDE = (sort) => {
  896. const { prop, order } = sort;
  897. if (!['created_at', 'expire_time'].includes(prop)) return;
  898. sortPropDE.value = prop; // 保存当前排序字段
  899. sortOrderDE.value = order; // 保存当前排序方式
  900. DETableData();
  901. };
  902. // 深度探索获取表格数据
  903. const DETableData = async () => {
  904. try {
  905. tableLoadingDE.value = true;
  906. const requestParams = {
  907. token: token,
  908. dccode: searchFormDE.dccode,
  909. dcname: searchFormDE.dcname,
  910. is_login: searchFormDE.is_login,
  911. inviter: searchFormDE.inviter,
  912. market: searchFormDE.market,
  913. user_role: searchFormDE.user_role,
  914. indicator_id: searchFormDE.indicator_id,
  915. sort_field: sortPropDE.value,
  916. sort_order: sortOrderDE.value,
  917. page: currentPageDE.value,
  918. page_size: pageSizeDE.value
  919. };
  920. const data = await userDEListApi(requestParams);
  921. tableDataDE.value = data.list
  922. datatotalDE.value = data.total
  923. } catch (error) {
  924. console.error('获取表格数据失败:', error);
  925. tableDataDE.value = [];
  926. datatotalDE.value = 0
  927. } finally {
  928. tableLoadingDE.value = false;
  929. }
  930. };
  931. // 深度探索搜索按钮
  932. const searchDE = () => {
  933. currentPageDE.value = 1;
  934. DETableData();
  935. };
  936. // 深度探索重置按钮
  937. const resetBnDE = () => {
  938. searchFormDE.dccode = '';
  939. searchFormDE.dcname = '';
  940. searchFormDE.is_login = '';
  941. searchFormDE.inviter = '';
  942. searchFormDE.market = '';
  943. searchFormDE.user_role = '';
  944. searchFormDE.indicator_id = '';
  945. sortPropDE.value = null;
  946. sortOrderDE.value = null;
  947. currentPageDE.value = 1;
  948. pageSizeDE.value = 10;
  949. DETableData();
  950. };
  951. // 深度探索导出Excel列表按钮
  952. const exportExcelDE = async () => {
  953. const requestParams = {
  954. token: token,
  955. dccode: searchFormDE.dccode,
  956. dcname: searchFormDE.dcname,
  957. is_login: searchFormDE.is_login,
  958. inviter: searchFormDE.inviter,
  959. market: searchFormDE.market,
  960. user_role: searchFormDE.user_role,
  961. indicator_id: searchFormDE.indicator_id,
  962. sort_field: sortPropDE.value,
  963. sort_order: sortOrderDE.value
  964. };
  965. const data = await exportDeepExploreApi(requestParams);
  966. if (data != '') {
  967. ElMessage.success('已导出');
  968. }
  969. };
  970. // 深度探索查看导出列表按钮
  971. const exportListDE = () => {
  972. router.push({
  973. path: "/userPermissions/export"
  974. });
  975. };
  976. // 深度探索开通权限按钮
  977. const enableAccessDE = () => {
  978. dialogVisibleDE.value = true;
  979. addOrUpdataDE.value = 1;
  980. };
  981. // 深度探索编辑按钮
  982. const handleEditDE = (row) => {
  983. dialogVisibleDE.value = true;
  984. hlidsInputDE.value = row.dccode;
  985. deadline.value = row.expire_time;
  986. indicator_id.value = row.indicator_id.split("、").filter(Boolean).map(Number);
  987. };
  988. // 深度探索权限详情按钮
  989. const handleDetailsDE = (dccode) =>{
  990. openDetail(dccode)
  991. }
  992. // 深度探索操作日志按钮
  993. const handleLogDE = (dccode) => {
  994. router.push({
  995. path: "/userPermissions/logDeepExplore",
  996. query: { dccode: dccode }
  997. });
  998. };
  999. // 弹框显隐控制
  1000. const dialogVisibleDE = ref(false);
  1001. // 开通权限表单
  1002. const hlidsInputDE = ref('');
  1003. const indicator_id = ref([]);
  1004. const timeType = ref('');
  1005. const expireTime = ref('');
  1006. const delayValue = ref('');
  1007. const delayUnit = ref('');
  1008. const remark = ref('');
  1009. const operator = ref('');
  1010. // 判断开通还是编辑
  1011. const addOrUpdataDE = ref(0);
  1012. // 编辑回显内容
  1013. const deadline = ref('');
  1014. // 将数组转为顿号拼接的字符串
  1015. const indicatorStr = computed(() => {
  1016. return indicator_id.value?.join('、') || '';
  1017. });
  1018. // 禁用当前日期之前的日期(当天0点之前的时间)
  1019. const disabledDate = (time) => {
  1020. return time.getTime() < new Date().getTime() - 8.64e7;
  1021. };
  1022. // 格式化日期
  1023. const formatDate = (date) => {
  1024. if (!date) return '';
  1025. const year = date.getFullYear();
  1026. const month = String(date.getMonth() + 1).padStart(2, '0');
  1027. const day = String(date.getDate()).padStart(2, '0');
  1028. return `${year}/${month}/${day}`;
  1029. };
  1030. // 禁止为小数
  1031. const handleDelayInput = () => {
  1032. if (delayValue.value !== null && delayValue.value !== undefined) {
  1033. delayValue.value = Math.floor(delayValue.value);
  1034. }
  1035. };
  1036. // 校验HLid
  1037. const checkHlidsDE = () => {
  1038. // 非空
  1039. if (!hlidsInputDE.value.trim()) {
  1040. ElMessage.error('请输入HLid');
  1041. return false;
  1042. }
  1043. // 处理输入:去空、去重,转数组
  1044. const hlidList = hlidsInputDE.value.split('\n')
  1045. .map(item => item.trim())
  1046. .filter(item => item)
  1047. .filter((item, index, self) => self.indexOf(item) === index); // 去重
  1048. // 数量校验(最多1000个)
  1049. if (hlidList.length > 1000) {
  1050. ElMessage.error('HLid数量不能超过1000个');
  1051. return false;
  1052. }
  1053. // 格式校验(8位数字)
  1054. const hlidReg = /^\d{8}$/;
  1055. for (const hlid of hlidList) {
  1056. if (!hlidReg.test(hlid)) {
  1057. ElMessage.error(`有HLid格式错误:${hlid},请重新输入`);
  1058. return false;
  1059. }
  1060. }
  1061. return true;
  1062. };
  1063. // 校验指标
  1064. const checkmodel = () => {
  1065. if (indicator_id.value.length === 0) {
  1066. ElMessage.error('请至少选择一个指标');
  1067. return false;
  1068. }
  1069. return true;
  1070. };
  1071. // 校验时间
  1072. const checkTime = () => {
  1073. if (timeType.value === 'expire') {
  1074. // 到期时间
  1075. if (!expireTime.value) {
  1076. ElMessage.error('请选择到期时间');
  1077. return false;
  1078. }
  1079. } else if (timeType.value === 'delay') {
  1080. // 延期时间
  1081. if (!delayValue.value || !delayUnit.value) {
  1082. ElMessage.error('延期时间必须填写完整(数值+单位)');
  1083. return false;
  1084. }
  1085. const delayNum = Number(delayValue.value);
  1086. if (isNaN(delayNum) || delayNum < 0) {
  1087. ElMessage.error('延期时间不能为负数,请输入有效正数');
  1088. return false;
  1089. }
  1090. if (delayNum === 0) {
  1091. ElMessage.error('延期时间不能为0,请输入有效正数');
  1092. return false;
  1093. }
  1094. } else {
  1095. ElMessage.error('请设置权限时间');
  1096. return false;
  1097. }
  1098. return true;
  1099. };
  1100. // 校验备注
  1101. const checkRemark = () => {
  1102. if (!remark.value.trim()) {
  1103. ElMessage.error('请输入备注');
  1104. return false;
  1105. }
  1106. return true;
  1107. };
  1108. // 防抖
  1109. const NoshakeDE = ref(false)
  1110. // 提交表单
  1111. const submitFormDE = async () => {
  1112. // 防抖
  1113. if (NoshakeDE.value) return;
  1114. NoshakeDE.value = true;
  1115. // 表单校验
  1116. if (!checkHlidsDE() || !checkmodel() || !checkTime() || !checkRemark()) {
  1117. NoshakeDE.value = false;
  1118. return;
  1119. }
  1120. try {
  1121. // 组装后端要求的参数格式
  1122. const requestParams = {
  1123. token: token,
  1124. // HLid
  1125. hlids: hlidsInputDE.value.split('\n')
  1126. .map(item => item.trim())
  1127. .filter(item => item)
  1128. .join('\n'),
  1129. // 指标
  1130. indicator_id: indicatorStr.value,
  1131. // 备注
  1132. remark: remark.value.trim(),
  1133. // 操作人
  1134. ...(operator.value.trim() && { operator: operator.value.trim() }),
  1135. // 时间参数
  1136. ...(timeType.value === 'expire'
  1137. ? { expire_time: formatDate(expireTime.value) }
  1138. : {
  1139. [delayUnit.value]: Number(delayValue.value)
  1140. })
  1141. };
  1142. console.log('传给后端的参数:', requestParams);
  1143. // 调用后端接口
  1144. await exitDEApi(requestParams);
  1145. ElMessage.success(addOrUpdataDM.value === 1 ? '成功添加用户权限' : '成功修改用户权限');
  1146. // 重置表单并关闭弹框
  1147. resetForm();
  1148. dialogVisibleDE.value = false;
  1149. addOrUpdataDE.value = 0;
  1150. // 重新获取表格
  1151. DETableData();
  1152. } catch (error) {
  1153. ElMessage.error('添加权限失败,请重试');
  1154. } finally {
  1155. NoshakeDE.value = false;
  1156. }
  1157. };
  1158. // 深度探索重置表单数据
  1159. const resetForm = () => {
  1160. hlidsInputDE.value = '';
  1161. indicator_id.value = [];
  1162. timeType.value = '';
  1163. expireTime.value = '';
  1164. delayValue.value = '';
  1165. delayUnit.value = '';
  1166. remark.value = '';
  1167. operator.value = '';
  1168. };
  1169. // 深度探索取消表单
  1170. const cancelDE = () => {
  1171. resetForm();
  1172. dialogVisibleDE.value = false;
  1173. addOrUpdataDE.value = 0;
  1174. };
  1175. // 深度探索权限详情弹窗开关
  1176. const showPermissionDetail = ref(false);
  1177. // 深度探索权限详情弹窗数据
  1178. const HLid = ref('');
  1179. const permissionData = ref([]);
  1180. // 深度探索权限详情获取数据并开启弹窗
  1181. const openDetail = async(dccode) => {
  1182. HLid.value = dccode
  1183. // 后端调用
  1184. const res = await detailDEApi({
  1185. token: token,
  1186. dccode: dccode
  1187. })
  1188. permissionData.value = res
  1189. // 显示弹窗
  1190. showPermissionDetail.value = true;
  1191. };
  1192. </script>
  1193. <style scoped>
  1194. /* 父容器 */
  1195. .page-container {
  1196. position: relative;
  1197. min-height: 600px;
  1198. }
  1199. /* 搜索区域 */
  1200. .search-container {
  1201. display: flex;
  1202. height: auto;
  1203. flex-direction: column;
  1204. justify-content: center;
  1205. align-items: flex-start;
  1206. gap: 12px;
  1207. align-self: stretch;
  1208. border-radius: 8px;
  1209. background: #FEFAF9;
  1210. box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
  1211. padding: 15px;
  1212. margin-bottom: 20px;
  1213. }
  1214. /* 搜索表单 */
  1215. .search-form {
  1216. display: flex;
  1217. align-items: center;
  1218. width: 100%;
  1219. gap: 15px;
  1220. flex-wrap: wrap;
  1221. row-gap: 8px;
  1222. }
  1223. /* 搜索组 */
  1224. .search-group {
  1225. }
  1226. .search-group1{
  1227. display: flex;
  1228. align-items: center;
  1229. gap: 15px;
  1230. }
  1231. .search-group2{
  1232. display: flex;
  1233. margin-top: 15px;
  1234. align-items: center;
  1235. gap: 15px;
  1236. }
  1237. /* 单个搜索项 */
  1238. .search-item {
  1239. display: flex;
  1240. align-items: center;
  1241. gap: 6px;
  1242. }
  1243. /* 搜索标签文字 */
  1244. .form-label {
  1245. font-weight: 800 !important;
  1246. font-size: 15px;
  1247. text-align: left;
  1248. color: #333;
  1249. margin-top: 13px;
  1250. font-family: "SimHei", "Heiti SC", "Microsoft YaHei", sans-serif !important;
  1251. }
  1252. /* 按钮组 */
  1253. .button-group {
  1254. display: flex;
  1255. align-items: center;
  1256. gap: 0px !important;
  1257. margin-left: auto;
  1258. }
  1259. /* 按钮样式 */
  1260. .button-group .el-button {
  1261. padding: 6px 10px !important;
  1262. font-size: 14px !important;
  1263. height: 36px !important;
  1264. }
  1265. /* 表格样式 */
  1266. .table-rounded {
  1267. border-radius: 12px !important;
  1268. overflow: hidden !important;
  1269. border: 1px solid #e4e7ed !important;
  1270. height: 650px;
  1271. }
  1272. .table-roundedDE {
  1273. border-radius: 12px !important;
  1274. overflow: hidden !important;
  1275. border: 1px solid #e4e7ed !important;
  1276. height: 650px;
  1277. }
  1278. .table-header {
  1279. text-align: center !important;
  1280. font-weight: 800 !important;
  1281. font-size: 15px !important;
  1282. color: #333 !important;
  1283. background-color: #f8f9fa !important;
  1284. }
  1285. .el-table__cell {
  1286. border-right: none !important;
  1287. border-bottom: 1px solid #e4e7ed !important;
  1288. }
  1289. .el-table__header th.el-table__cell {
  1290. border-right: none !important;
  1291. border-bottom: 1px solid #e4e7ed !important;
  1292. }
  1293. .el-table__row:hover .el-table__cell {
  1294. background-color: #fafafa !important;
  1295. }
  1296. /* 分页组件样式 */
  1297. .demo-pagination-block {
  1298. display: flex;
  1299. width: 100%;
  1300. height: 44px;
  1301. padding: 0 16px;
  1302. align-items: center;
  1303. gap: 16px;
  1304. position: absolute;
  1305. margin-top: 10px;
  1306. border-radius: 0 0 3px 3px;
  1307. border-top: 1px solid #EAEAEA;
  1308. background: #FEFBFB;
  1309. box-sizing: border-box;
  1310. }
  1311. /* 添加/修改样式 */
  1312. .form-item {
  1313. margin-bottom: 24px;
  1314. padding-left: 20px;
  1315. padding-right: 20px;
  1316. text-align: left;
  1317. }
  1318. .form-label {
  1319. display: block;
  1320. margin-bottom: 8px;
  1321. font-weight: 500;
  1322. }
  1323. .radio-group {
  1324. display: flex;
  1325. flex-direction: column;
  1326. gap: 12px;
  1327. align-items: flex-start;
  1328. }
  1329. .radio-item {
  1330. display: flex;
  1331. align-items: center;
  1332. }
  1333. .radio-item span {
  1334. margin-right: 8px;
  1335. }
  1336. .tip {
  1337. font-size: 12px;
  1338. color: #909399;
  1339. margin-top: 4px;
  1340. }
  1341. .dialog-footer {
  1342. display: flex;
  1343. justify-content: flex-end;
  1344. gap: 16px;
  1345. margin-top: 20px;
  1346. }
  1347. .inline-form-item {
  1348. display: flex;
  1349. align-items: flex-start;
  1350. gap: 12px;
  1351. }
  1352. .inline-form-item .form-label {
  1353. display: inline-block;
  1354. margin-bottom: 0;
  1355. width: 60px;
  1356. text-align: left;
  1357. padding-right: 12px;
  1358. }
  1359. .info-container {
  1360. display: flex;
  1361. align-items: center;
  1362. gap: 40px;
  1363. padding: 0 20px 18px;
  1364. color: #333;
  1365. font-size: 16px;
  1366. }
  1367. .info-item {
  1368. white-space: nowrap;
  1369. }
  1370. /* Tab容器 */
  1371. .tab-group {
  1372. display: flex;
  1373. gap: 12px;
  1374. justify-content: flex-start;
  1375. margin: 4px 0;
  1376. padding-left: 2px;
  1377. }
  1378. /* Tab按钮 */
  1379. .tab-btn {
  1380. width: 120px;
  1381. padding: 6px 0;
  1382. text-align: center;
  1383. border: 1px solid #ff0000;
  1384. border-radius: 4px;
  1385. background-color: #ffffff;
  1386. color: #ff0000;
  1387. font-size: 14px;
  1388. cursor: pointer;
  1389. transition: all 0.2s;
  1390. outline: none;
  1391. }
  1392. /* Tab选中样式 */
  1393. .tab-btn.active {
  1394. background-color: #ff0000;
  1395. color: #ffffff;
  1396. }
  1397. /* hover效果优化 */
  1398. .tab-btn:not(.active):hover {
  1399. background-color: #fff5f5;
  1400. }
  1401. /* 搜索区域(深度探索) */
  1402. .search-containerDE {
  1403. display: flex;
  1404. height: auto;
  1405. flex-direction: column;
  1406. justify-content: center;
  1407. align-items: flex-start;
  1408. gap: 12px;
  1409. align-self: stretch;
  1410. border-radius: 8px;
  1411. background: #FEFAF9;
  1412. box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
  1413. padding: 15px;
  1414. margin-bottom: 20px;
  1415. }
  1416. /* 搜索表单(深度探索) */
  1417. .search-formDE {
  1418. display: flex;
  1419. align-items: center;
  1420. width: 100%;
  1421. gap: 15px;
  1422. flex-wrap: wrap;
  1423. row-gap: 8px;
  1424. }
  1425. /* 搜索组 */
  1426. .search-groupDE {
  1427. }
  1428. .search-groupDE1{
  1429. display: flex;
  1430. align-items: center;
  1431. gap: 15px;
  1432. }
  1433. .search-groupDE2{
  1434. display: flex;
  1435. margin-top: 15px;
  1436. align-items: center;
  1437. gap: 15px;
  1438. }
  1439. /* 单个搜索项(深度探索) */
  1440. .search-itemDE {
  1441. display: flex;
  1442. align-items: center;
  1443. gap: 6px;
  1444. }
  1445. /* 搜索标签文字(深度探索) */
  1446. .form-labelDE {
  1447. font-weight: 800 !important;
  1448. font-size: 15px;
  1449. text-align: left;
  1450. color: #333;
  1451. margin-top: 13px;
  1452. font-family: "SimHei", "Heiti SC", "Microsoft YaHei", sans-serif !important;
  1453. }
  1454. .form-labelDE {
  1455. display: block;
  1456. margin-bottom: 8px;
  1457. font-weight: 500;
  1458. }
  1459. /* 按钮组(深度探索) */
  1460. .button-groupDE {
  1461. display: flex;
  1462. align-items: center;
  1463. gap: 0px !important;
  1464. margin-left: auto;
  1465. }
  1466. /* 按钮样式(深度探索) */
  1467. .button-groupDE .el-button {
  1468. padding: 6px 10px !important;
  1469. font-size: 14px !important;
  1470. height: 36px !important;
  1471. }
  1472. /* 文本溢出省略样式(深度探索) */
  1473. .ellipsis-text {
  1474. display: inline-block;
  1475. width: 100%;
  1476. white-space: nowrap;
  1477. overflow: hidden;
  1478. text-overflow: ellipsis;
  1479. vertical-align: middle;
  1480. }
  1481. /* 开通/编辑指标复选(深度探索) */
  1482. .indicator-checkbox-group {
  1483. display: flex;
  1484. flex-wrap: wrap;
  1485. gap: 8px;
  1486. margin-top: 8px;
  1487. width: 100%
  1488. }
  1489. .indicator-checkbox-item {
  1490. flex: 0 0 calc(20% - 5px);
  1491. box-sizing: border-box;
  1492. padding: 4px 0;
  1493. }
  1494. :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
  1495. background-color: #ff0000 !important;
  1496. border-color: #ff0000 !important;
  1497. }
  1498. :deep(.el-checkbox__input.is-checked .el-checkbox__inner::after) {
  1499. border-color: #fff !important;
  1500. }
  1501. :deep(.el-checkbox__input:hover .el-checkbox__inner) {
  1502. border-color: #ff0000 !important;
  1503. }
  1504. :deep(.el-checkbox__input:focus .el-checkbox__inner) {
  1505. box-shadow: 0 0 0 2px rgba(255, 0, 0, 0.2) !important;
  1506. }
  1507. :deep(.el-checkbox__label) {
  1508. color: #333 !important;
  1509. font-size: 14px !important;
  1510. }
  1511. /* 权限详情(深度探索) */
  1512. .permission-detail-dialog {
  1513. --el-dialog-padding-primary: 15px;
  1514. }
  1515. .detail-container {
  1516. background-color: #fff1f0;
  1517. border-radius: 6px;
  1518. padding: 15px;
  1519. }
  1520. .hlid-item {
  1521. margin-bottom: 25px;
  1522. }
  1523. .label {
  1524. color: #666;
  1525. font-weight: 500;
  1526. }
  1527. .value {
  1528. color: #333;
  1529. }
  1530. .expire-section {
  1531. margin-top: 10px;
  1532. }
  1533. .section-title {
  1534. font-size: 16px;
  1535. color: #333;
  1536. margin-bottom: 10px;
  1537. font-weight: bold;
  1538. }
  1539. .indicator-list {
  1540. display: flex;
  1541. flex-direction: column;
  1542. gap: 8px;
  1543. }
  1544. .indicator-item {
  1545. padding: 6px 0;
  1546. display: flex;
  1547. align-items: center;
  1548. }
  1549. .indicator-name {
  1550. color: #666;
  1551. font-size: 14px;
  1552. }
  1553. .expire-time {
  1554. color: #333;
  1555. font-size: 14px;
  1556. margin-left: 8px;
  1557. }
  1558. .expired-tag {
  1559. background-color: #ffccd5;
  1560. color: #f56c6c;
  1561. font-size: 12px;
  1562. padding: 2px 8px;
  1563. border-radius: 4px;
  1564. margin-left: 8px;
  1565. }
  1566. </style>