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.

1021 lines
26 KiB

  1. <template>
  2. <div class="page-container">
  3. <!-- 搜索区域 -->
  4. <div class="search-containerDE" @keyup.enter="searchDE">
  5. <!-- 输入项区域 -->
  6. <div class="search-formDE">
  7. <div class="search-groupDE">
  8. <div class="search-groupDE1">
  9. <div class="search-itemDE">
  10. <span class="form-labelDE">账号</span>
  11. <el-input
  12. v-model="searchFormDE.dccode"
  13. placeholder="请输入账号"
  14. clearable
  15. style="height: 36px; width: 140px;"
  16. />
  17. </div>
  18. <div class="search-itemDE">
  19. <span class="form-labelDE">姓名</span>
  20. <el-input
  21. v-model="searchFormDE.dcname"
  22. placeholder="请输入姓名"
  23. clearable
  24. style="height: 36px; width: 180px;"
  25. />
  26. </div>
  27. <div class="search-itemDE">
  28. <span class="form-labelDE">归属</span>
  29. <el-input
  30. v-model="searchFormDE.inviter"
  31. placeholder="请输入归属账号"
  32. clearable
  33. style="height: 36px; width: 180px;"
  34. />
  35. </div>
  36. </div>
  37. <div class="search-groupDE2">
  38. <div class="search-itemDE">
  39. <span class="form-labelDE">客户类型</span>
  40. <el-select
  41. v-model="searchFormDE.user_role"
  42. placeholder="请选择客户类型"
  43. clearable
  44. style="height: 36px; width: 160px;"
  45. >
  46. <el-option label="非网" value="2" />
  47. <el-option label="会员" value="1" />
  48. </el-select>
  49. </div>
  50. <div class="search-itemDE">
  51. <span class="form-labelDE">地区</span>
  52. <el-select
  53. v-model="searchFormDE.market"
  54. placeholder="请选择地区"
  55. clearable
  56. filterable
  57. style="height: 36px; width: 160px;"
  58. :loading="isRegionLoading"
  59. >
  60. <el-option
  61. v-for="region in regionList"
  62. :key="region.ID"
  63. :label="region.Name"
  64. :value="region.ID"
  65. />
  66. </el-select>
  67. </div>
  68. <div class="search-itemDE">
  69. <span class="form-labelDE">指标名称</span>
  70. <el-select
  71. v-model="searchFormDE.indicator_id"
  72. placeholder="请选择指标名称"
  73. clearable
  74. style="height: 36px; width: 160px;"
  75. >
  76. <el-option
  77. v-for="item in indicatorOptions"
  78. :key="item.id"
  79. :label="item.name"
  80. :value="item.id"
  81. />
  82. </el-select>
  83. </div>
  84. </div>
  85. </div>
  86. <!-- 按钮组 -->
  87. <div class="button-groupDE">
  88. <el-button type="primary" @click="searchDE">搜索</el-button>
  89. <el-button type="danger" @click="enableAccessDE">开通权限</el-button>
  90. <el-button type="success" @click="exportExcelDE">导出Excel列表</el-button>
  91. <el-button color="#626aef" @click="exportListDE">查看导出列表</el-button>
  92. <el-button type="primary" @click="resetBnDE">重置</el-button>
  93. </div>
  94. </div>
  95. </div>
  96. <!-- 数据 -->
  97. <el-table
  98. :data="tableDataDE"
  99. style="width: 100%; margin-top: 20px;"
  100. header-cell-class-name="table-header"
  101. @sort-change="handleSortChangeDE"
  102. :default-sort="{ prop: null, order: null }"
  103. class="table-roundedDE"
  104. :loading="tableLoadingDE"
  105. >
  106. <el-table-column prop="id" label="序号" align="center" header-align="center" width="80">
  107. <template #default="scope">
  108. {{ (currentPageDE - 1) * pageSizeDE + scope.$index + 1 }}
  109. </template>
  110. </el-table-column>
  111. <el-table-column prop="dccode" label="账号" align="center" header-align="center"/>
  112. <el-table-column prop="dcname" label="姓名" align="center" header-align="center"/>
  113. <el-table-column prop="inviter" label="归属" align="center" header-align="center"/>
  114. <el-table-column prop="name" label="指标名称" align="center" header-align="center" width="200">
  115. <template #default="scope">
  116. <el-tooltip
  117. effect="dark"
  118. :content="scope.row.name"
  119. placement="top"
  120. >
  121. <span class="ellipsis-text">{{ scope.row.name }}</span>
  122. </el-tooltip>
  123. </template>
  124. </el-table-column>
  125. <el-table-column prop="created_at" label="开通时间" align="center" header-align="center" sortable="custom" width="200"/>
  126. <el-table-column prop="expire_time" label="到期时间" align="center" header-align="center" sortable="custom" width="200"/>
  127. <el-table-column label="操作" align="center" header-align="center" width="200">
  128. <template #default="scope">
  129. <el-button type="text" @click="handleEditDE(scope.row)">编辑</el-button>
  130. <el-button type="text" @click="handleDetailsDE(scope.row.dccode)">权限详情</el-button>
  131. <el-button type="text" @click="handleLogDE(scope.row.dccode)">操作日志</el-button>
  132. </template>
  133. </el-table-column>
  134. </el-table>
  135. <!-- 分页组件 -->
  136. <div class="demo-pagination-block">
  137. <el-pagination
  138. @size-change="handleSizeChangeDE"
  139. @current-change="handleCurrentChangeDE"
  140. :current-page="currentPageDE"
  141. :page-sizes="[10, 20, 50, 100]"
  142. :page-size="pageSizeDE"
  143. layout="total, sizes, prev, pager, next, jumper"
  144. :total= "datatotalDE"
  145. />
  146. </div>
  147. <!-- 开通/编辑 -->
  148. <el-dialog v-model="dialogVisibleDE" :title="addOrUpdataDE === 1 ? '添加权限' : '设置'" width="550px" :before-close="cancelDE">
  149. <!-- 设置用户 -->
  150. <div class="form-item" v-if="addOrUpdataDE === 1">
  151. <label class="form-label">设置用户</label>
  152. <el-input type="textarea" v-model="hlidsInputDE" rows=10
  153. placeholder="请输入HLid...
  154. 示例
  155. 90048004
  156. 90048005
  157. 90048006"
  158. />
  159. <div class="tip">支持批量输入每次最多1000个手动/Excel粘贴均可</div>
  160. </div>
  161. <!-- 编辑回显 -->
  162. <div class="info-container" v-if="addOrUpdataDE === 0">
  163. <span class="info-item">Homily ID{{ hlidsInputDE }}</span>
  164. <span class="info-item">当前到期时间{{ deadline.split(' ')[0] }}</span>
  165. </div>
  166. <!-- 设置指标 -->
  167. <div class="form-item">
  168. <label class="form-label">选择模板</label>
  169. <el-checkbox-group v-model="indicator_id" class="indicator-checkbox-group">
  170. <el-checkbox
  171. v-for="item in indicatorOptions"
  172. :key="item.id"
  173. :label="item.id"
  174. class="indicator-checkbox-item"
  175. >
  176. {{ item.name }}
  177. </el-checkbox>
  178. </el-checkbox-group>
  179. </div>
  180. <!-- 设置权限时间 -->
  181. <div class="form-item">
  182. <label class="form-label">设置权限时间</label>
  183. <el-radio-group v-model="timeType" class="radio-group">
  184. <el-radio label="expire" class="radio-item">
  185. <span>到期时间</span>
  186. <el-date-picker
  187. v-model="expireTime"
  188. type="date"
  189. placeholder="请选择到期日期"
  190. :disabled-date="disabledDate"
  191. style="width: 220px; margin-left: 8px;"
  192. />
  193. </el-radio>
  194. <el-radio label="delay" class="radio-item">
  195. <span>延期时间</span>
  196. <el-input
  197. v-model.number="delayValue"
  198. type="number"
  199. style="width: 60px; margin: 0 8px;"
  200. placeholder="1"
  201. @input="handleDelayInput"
  202. />
  203. <el-select v-model="delayUnit" placeholder="请选择" style="width: 150px;">
  204. <el-option label="年" value="year"></el-option>
  205. <el-option label="月" value="month"></el-option>
  206. <el-option label="周" value="week"></el-option>
  207. <el-option label="日" value="day"></el-option>
  208. </el-select>
  209. </el-radio>
  210. </el-radio-group>
  211. </div>
  212. <!-- 备注-->
  213. <div class="form-item inline-form-item">
  214. <label class="form-label">备注</label>
  215. <el-input
  216. type="textarea"
  217. v-model="remark"
  218. rows=3
  219. placeholder="请输入备注..."
  220. maxlength="150"
  221. show-word-limit
  222. />
  223. </div>
  224. <!-- 操作人 -->
  225. <div class="form-item inline-form-item">
  226. <label class="form-label">操作人</label>
  227. <el-input v-model="operator" placeholder="请填写操作人"/>
  228. </div>
  229. <!-- 按钮区域 -->
  230. <div class="dialog-footer">
  231. <el-button type="default" plain @click="cancelDE">取消</el-button>
  232. <el-button type="primary" @click="submitFormDE" style="background-color: #ff0000; border-color: #ff0000;">提交</el-button>
  233. </div>
  234. </el-dialog>
  235. <!-- 权限详情 -->
  236. <el-dialog
  237. v-model="showPermissionDetail"
  238. title="权限详情"
  239. width="400px"
  240. :close-on-click-modal="false"
  241. :show-close="true"
  242. class="permission-detail-dialog"
  243. >
  244. <div class="detail-container">
  245. <!-- HLid 信息 -->
  246. <div class="hlid-item">
  247. <span class="label">Homily ID</span>
  248. <span class="value">{{ HLid }}</span>
  249. </div>
  250. <!-- 到期时间区域 -->
  251. <div class="expire-section">
  252. <h3 class="section-title">到期时间</h3>
  253. <div class="indicator-list">
  254. <div
  255. v-for="(item, index) in permissionData"
  256. :key="index"
  257. class="indicator-item"
  258. >
  259. <span class="indicator-name">{{ item.name }}</span>
  260. <template v-if="item.is_expired === 1">
  261. <span class="expired-tag">已到期</span>
  262. </template>
  263. <template v-else>
  264. <span class="expire-time">{{ item.expire_time.split(' ')[0] }}</span>
  265. </template>
  266. </div>
  267. </div>
  268. </div>
  269. </div>
  270. </el-dialog>
  271. </div>
  272. </template>
  273. <script setup>
  274. import { ref, reactive, onMounted, computed } from 'vue';
  275. import { ElMessage } from 'element-plus';
  276. import { marketListApi, indicatorListApi, userDEListApi, exportDeepExploreApi, exitDEApi, detailDEApi } from '../../api/userPermissions'
  277. import router from '../../router';
  278. // token
  279. const token = localStorage.getItem('token')
  280. // 地区下拉框
  281. const regionList = ref([]);
  282. const isRegionLoading = ref(false);
  283. // 获取地区列表
  284. const fetchRegionList = async () => {
  285. try {
  286. isRegionLoading.value = true;
  287. const data = await marketListApi({
  288. token: token,
  289. app_form: "en"
  290. });
  291. regionList.value = data.list;
  292. } catch (error) {
  293. console.error('获取地区列表失败:', error);
  294. regionList.value = [];
  295. } finally {
  296. isRegionLoading.value = false;
  297. }
  298. };
  299. // 深度探索指标选项
  300. const indicatorOptions = ref([]);
  301. const indicatorList = async () => {
  302. try {
  303. const data = await indicatorListApi({token: token});
  304. indicatorOptions.value = data.list;
  305. } catch (error) {
  306. console.error('获取指标列表失败:', error);
  307. indicatorOptions.value = [];
  308. }
  309. }
  310. // 深度探索搜索表单
  311. const searchFormDE = reactive({
  312. dccode: '',
  313. dcname: '',
  314. is_login:'',
  315. inviter: '',
  316. market: '',
  317. user_role: '',
  318. indicator_id: ''
  319. });
  320. // 深度探索排序参数
  321. const sortPropDE = ref(null);
  322. const sortOrderDE = ref(null);
  323. // 深度探索分页参数
  324. const currentPageDE = ref(1);
  325. const pageSizeDE = ref(10);
  326. // 深度探索表格数据
  327. const tableDataDE = ref([]);
  328. const tableLoadingDE = ref(false);
  329. const datatotalDE = ref(0)
  330. // 深度探索分页方法
  331. const handleSizeChangeDE = (val) => {
  332. pageSizeDE.value = val;
  333. DETableData();
  334. console.log(`每页 ${val}`);
  335. };
  336. const handleCurrentChangeDE = (val) => {
  337. currentPageDE.value = val;
  338. DETableData();
  339. console.log(`当前页: ${val}`);
  340. };
  341. // 深度探索排序事件
  342. const handleSortChangeDE = (sort) => {
  343. const { prop, order } = sort;
  344. if (!['created_at', 'expire_time'].includes(prop)) return;
  345. sortPropDE.value = prop; // 保存当前排序字段
  346. sortOrderDE.value = order; // 保存当前排序方式
  347. DETableData();
  348. };
  349. // 深度探索获取表格数据
  350. const DETableData = async () => {
  351. try {
  352. tableLoadingDE.value = true;
  353. const requestParams = {
  354. token: token,
  355. dccode: searchFormDE.dccode,
  356. dcname: searchFormDE.dcname,
  357. is_login: searchFormDE.is_login,
  358. inviter: searchFormDE.inviter,
  359. market: searchFormDE.market,
  360. user_role: searchFormDE.user_role,
  361. indicator_id: searchFormDE.indicator_id,
  362. sort_field: sortPropDE.value,
  363. sort_order: sortOrderDE.value,
  364. page: currentPageDE.value,
  365. page_size: pageSizeDE.value
  366. };
  367. const data = await userDEListApi(requestParams);
  368. tableDataDE.value = data.list
  369. datatotalDE.value = data.total
  370. } catch (error) {
  371. console.error('获取表格数据失败:', error);
  372. tableDataDE.value = [];
  373. datatotalDE.value = 0
  374. } finally {
  375. tableLoadingDE.value = false;
  376. }
  377. };
  378. // 深度探索搜索按钮
  379. const searchDE = () => {
  380. currentPageDE.value = 1;
  381. DETableData();
  382. };
  383. // 深度探索重置按钮
  384. const resetBnDE = () => {
  385. searchFormDE.dccode = '';
  386. searchFormDE.dcname = '';
  387. searchFormDE.is_login = '';
  388. searchFormDE.inviter = '';
  389. searchFormDE.market = '';
  390. searchFormDE.user_role = '';
  391. searchFormDE.indicator_id = '';
  392. sortPropDE.value = null;
  393. sortOrderDE.value = null;
  394. currentPageDE.value = 1;
  395. pageSizeDE.value = 10;
  396. DETableData();
  397. };
  398. // 深度探索导出Excel列表按钮
  399. const exportExcelDE = async () => {
  400. const requestParams = {
  401. token: token,
  402. dccode: searchFormDE.dccode,
  403. dcname: searchFormDE.dcname,
  404. is_login: searchFormDE.is_login,
  405. inviter: searchFormDE.inviter,
  406. market: searchFormDE.market,
  407. user_role: searchFormDE.user_role,
  408. indicator_id: searchFormDE.indicator_id,
  409. sort_field: sortPropDE.value,
  410. sort_order: sortOrderDE.value
  411. };
  412. const data = await exportDeepExploreApi(requestParams);
  413. if (data != '') {
  414. ElMessage.success('已导出');
  415. }
  416. };
  417. // 深度探索查看导出列表按钮
  418. const exportListDE = () => {
  419. router.push({
  420. path: "/userPermissions/export"
  421. });
  422. };
  423. // 深度探索开通权限按钮
  424. const enableAccessDE = () => {
  425. dialogVisibleDE.value = true;
  426. addOrUpdataDE.value = 1;
  427. };
  428. // 深度探索编辑按钮
  429. const handleEditDE = (row) => {
  430. dialogVisibleDE.value = true;
  431. hlidsInputDE.value = row.dccode;
  432. deadline.value = row.expire_time;
  433. indicator_id.value = row.indicator_id.split("。").filter(Boolean).map(Number);
  434. };
  435. // 深度探索权限详情按钮
  436. const handleDetailsDE = (dccode) =>{
  437. openDetail(dccode)
  438. }
  439. // 深度探索操作日志按钮
  440. const handleLogDE = (dccode) => {
  441. router.push({
  442. path: "/userPermissions/logDeepExplore",
  443. query: { dccode: dccode }
  444. });
  445. };
  446. // 弹框显隐控制
  447. const dialogVisibleDE = ref(false);
  448. // 开通权限表单
  449. const hlidsInputDE = ref('');
  450. const indicator_id = ref([]);
  451. const timeType = ref('');
  452. const expireTime = ref('');
  453. const delayValue = ref('');
  454. const delayUnit = ref('');
  455. const remark = ref('');
  456. const operator = ref('');
  457. // 判断开通还是编辑
  458. const addOrUpdataDE = ref(0);
  459. // 编辑回显内容
  460. const deadline = ref('');
  461. // 将数组转为顿号拼接的字符串
  462. const indicatorStr = computed(() => {
  463. return indicator_id.value?.join('。') || '';
  464. });
  465. // 禁用当前日期之前的日期(当天0点之前的时间)
  466. const disabledDate = (time) => {
  467. return time.getTime() < new Date().getTime() - 8.64e7;
  468. };
  469. // 格式化日期
  470. const formatDate = (date) => {
  471. if (!date) return '';
  472. const year = date.getFullYear();
  473. const month = String(date.getMonth() + 1).padStart(2, '0');
  474. const day = String(date.getDate()).padStart(2, '0');
  475. return `${year}/${month}/${day}`;
  476. };
  477. // 禁止为小数
  478. const handleDelayInput = () => {
  479. if (delayValue.value !== null && delayValue.value !== undefined) {
  480. delayValue.value = Math.floor(delayValue.value);
  481. }
  482. };
  483. // 校验HLid
  484. const checkHlidsDE = () => {
  485. // 非空
  486. if (!hlidsInputDE.value.trim()) {
  487. ElMessage.error('请输入HLid');
  488. return false;
  489. }
  490. // 处理输入:去空、去重,转数组
  491. const hlidList = hlidsInputDE.value.split('\n')
  492. .map(item => item.trim())
  493. .filter(item => item)
  494. .filter((item, index, self) => self.indexOf(item) === index); // 去重
  495. // 数量校验(最多1000个)
  496. if (hlidList.length > 1000) {
  497. ElMessage.error('HLid数量不能超过1000个');
  498. return false;
  499. }
  500. // 格式校验(8位数字)
  501. const hlidReg = /^\d{8}$/;
  502. for (const hlid of hlidList) {
  503. if (!hlidReg.test(hlid)) {
  504. ElMessage.error(`有HLid格式错误:${hlid},请重新输入`);
  505. return false;
  506. }
  507. }
  508. return true;
  509. };
  510. // 校验指标
  511. const checkmodel = () => {
  512. if (indicator_id.value.length === 0) {
  513. ElMessage.error('请至少选择一个指标');
  514. return false;
  515. }
  516. return true;
  517. };
  518. // 校验时间
  519. const checkTime = () => {
  520. if (timeType.value === 'expire') {
  521. // 到期时间
  522. if (!expireTime.value) {
  523. ElMessage.error('请选择到期时间');
  524. return false;
  525. }
  526. } else if (timeType.value === 'delay') {
  527. // 延期时间
  528. if (!delayValue.value || !delayUnit.value) {
  529. ElMessage.error('延期时间必须填写完整(数值+单位)');
  530. return false;
  531. }
  532. const delayNum = Number(delayValue.value);
  533. if (isNaN(delayNum) || delayNum < 0) {
  534. ElMessage.error('延期时间不能为负数,请输入有效正数');
  535. return false;
  536. }
  537. if (delayNum === 0) {
  538. ElMessage.error('延期时间不能为0,请输入有效正数');
  539. return false;
  540. }
  541. } else {
  542. ElMessage.error('请设置权限时间');
  543. return false;
  544. }
  545. return true;
  546. };
  547. // 校验备注
  548. const checkRemark = () => {
  549. if (!remark.value.trim()) {
  550. ElMessage.error('请输入备注');
  551. return false;
  552. }
  553. return true;
  554. };
  555. // 防抖
  556. const NoshakeDE = ref(false)
  557. // 提交表单
  558. const submitFormDE = async () => {
  559. // 防抖
  560. if (NoshakeDE.value) return;
  561. NoshakeDE.value = true;
  562. // 表单校验
  563. if (!checkHlidsDE() || !checkmodel() || !checkTime() || !checkRemark()) {
  564. NoshakeDE.value = false;
  565. return;
  566. }
  567. try {
  568. // 组装后端要求的参数格式
  569. const requestParams = {
  570. token: token,
  571. // HLid
  572. hlids: hlidsInputDE.value.split('\n')
  573. .map(item => item.trim())
  574. .filter(item => item)
  575. .join('\n'),
  576. // 指标
  577. indicator_id: indicatorStr.value,
  578. // 备注
  579. remark: remark.value.trim(),
  580. // 操作人
  581. ...(operator.value.trim() && { operator: operator.value.trim() }),
  582. // 时间参数
  583. ...(timeType.value === 'expire'
  584. ? { expire_time: formatDate(expireTime.value) }
  585. : {
  586. [delayUnit.value]: Number(delayValue.value)
  587. })
  588. };
  589. console.log('传给后端的参数:', requestParams);
  590. // 调用后端接口
  591. await exitDEApi(requestParams);
  592. ElMessage.success(addOrUpdataDE.value === 1 ? '成功添加用户权限' : '成功修改用户权限');
  593. // 重置表单并关闭弹框
  594. resetForm();
  595. dialogVisibleDE.value = false;
  596. addOrUpdataDE.value = 0;
  597. // 重新获取表格
  598. DETableData();
  599. } catch (error) {
  600. ElMessage.error('添加权限失败,请重试');
  601. } finally {
  602. NoshakeDE.value = false;
  603. }
  604. };
  605. // 深度探索重置表单数据
  606. const resetForm = () => {
  607. hlidsInputDE.value = '';
  608. indicator_id.value = [];
  609. timeType.value = '';
  610. expireTime.value = '';
  611. delayValue.value = '';
  612. delayUnit.value = '';
  613. remark.value = '';
  614. operator.value = '';
  615. };
  616. // 深度探索取消表单
  617. const cancelDE = () => {
  618. resetForm();
  619. dialogVisibleDE.value = false;
  620. addOrUpdataDE.value = 0;
  621. };
  622. // 深度探索权限详情弹窗开关
  623. const showPermissionDetail = ref(false);
  624. // 深度探索权限详情弹窗数据
  625. const HLid = ref('');
  626. const permissionData = ref([]);
  627. // 深度探索权限详情获取数据并开启弹窗
  628. const openDetail = async(dccode) => {
  629. HLid.value = dccode
  630. // 后端调用
  631. const res = await detailDEApi({
  632. token: token,
  633. dccode: dccode
  634. })
  635. permissionData.value = res
  636. // 显示弹窗
  637. showPermissionDetail.value = true;
  638. };
  639. // 组件挂载时:获取地区列表 + 初始化表格数据
  640. onMounted(() => {
  641. fetchRegionList();
  642. indicatorList();
  643. DETableData();
  644. });
  645. </script>
  646. <style scoped>
  647. /* 父容器 */
  648. .page-container {
  649. position: relative;
  650. min-height: 600px;
  651. }
  652. /* 搜索区域(深度探索) */
  653. .search-containerDE {
  654. display: flex;
  655. height: auto;
  656. flex-direction: column;
  657. justify-content: center;
  658. align-items: flex-start;
  659. gap: 12px;
  660. align-self: stretch;
  661. border-radius: 8px;
  662. background: #FEFAF9;
  663. box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
  664. padding: 15px;
  665. margin-bottom: 20px;
  666. }
  667. /* 搜索表单(深度探索) */
  668. .search-formDE {
  669. display: flex;
  670. align-items: center;
  671. width: 100%;
  672. gap: 15px;
  673. flex-wrap: wrap;
  674. row-gap: 8px;
  675. }
  676. /* 搜索组 */
  677. .search-groupDE {
  678. }
  679. .search-groupDE1{
  680. display: flex;
  681. align-items: center;
  682. gap: 15px;
  683. }
  684. .search-groupDE2{
  685. display: flex;
  686. margin-top: 15px;
  687. align-items: center;
  688. gap: 15px;
  689. }
  690. /* 单个搜索项(深度探索) */
  691. .search-itemDE {
  692. display: flex;
  693. align-items: center;
  694. gap: 6px;
  695. }
  696. /* 搜索标签文字(深度探索) */
  697. .form-labelDE {
  698. font-weight: 800 !important;
  699. font-size: 15px;
  700. text-align: left;
  701. color: #333;
  702. margin-top: 13px;
  703. font-family: "SimHei", "Heiti SC", "Microsoft YaHei", sans-serif !important;
  704. }
  705. /* 按钮组(深度探索) */
  706. .button-groupDE {
  707. display: flex;
  708. align-items: center;
  709. gap: 0px !important;
  710. margin-left: auto;
  711. }
  712. /* 按钮样式(深度探索) */
  713. .button-groupDE .el-button {
  714. padding: 6px 10px !important;
  715. font-size: 14px !important;
  716. height: 36px !important;
  717. }
  718. /* 表格样式 */
  719. .table-roundedDE {
  720. border-radius: 12px !important;
  721. overflow: hidden !important;
  722. border: 1px solid #e4e7ed !important;
  723. height: 650px;
  724. }
  725. .table-header {
  726. text-align: center !important;
  727. font-weight: 800 !important;
  728. font-size: 15px !important;
  729. color: #333 !important;
  730. background-color: #f8f9fa !important;
  731. }
  732. .el-table__cell {
  733. border-right: none !important;
  734. border-bottom: 1px solid #e4e7ed !important;
  735. }
  736. .el-table__header th.el-table__cell {
  737. border-right: none !important;
  738. border-bottom: 1px solid #e4e7ed !important;
  739. }
  740. .el-table__row:hover .el-table__cell {
  741. background-color: #fafafa !important;
  742. }
  743. /* 分页组件样式 */
  744. .demo-pagination-block {
  745. display: flex;
  746. width: 100%;
  747. height: 44px;
  748. padding: 0 16px;
  749. align-items: center;
  750. gap: 16px;
  751. position: absolute;
  752. margin-top: 10px;
  753. border-radius: 0 0 3px 3px;
  754. border-top: 1px solid #EAEAEA;
  755. background: #FEFBFB;
  756. box-sizing: border-box;
  757. }
  758. /* 添加/修改样式 */
  759. .form-item {
  760. margin-bottom: 24px;
  761. padding-left: 20px;
  762. padding-right: 20px;
  763. text-align: left;
  764. }
  765. .form-label {
  766. display: block;
  767. margin-bottom: 8px;
  768. font-weight: 500;
  769. }
  770. .radio-group {
  771. display: flex;
  772. flex-direction: column;
  773. gap: 12px;
  774. align-items: flex-start;
  775. }
  776. .radio-item {
  777. display: flex;
  778. align-items: center;
  779. }
  780. .radio-item span {
  781. margin-right: 8px;
  782. }
  783. .tip {
  784. font-size: 12px;
  785. color: #909399;
  786. margin-top: 4px;
  787. }
  788. .dialog-footer {
  789. display: flex;
  790. justify-content: flex-end;
  791. gap: 16px;
  792. margin-top: 20px;
  793. }
  794. .inline-form-item {
  795. display: flex;
  796. align-items: flex-start;
  797. gap: 12px;
  798. }
  799. .inline-form-item .form-label {
  800. display: inline-block;
  801. margin-bottom: 0;
  802. width: 60px;
  803. text-align: left;
  804. padding-right: 12px;
  805. }
  806. .info-container {
  807. display: flex;
  808. align-items: center;
  809. gap: 20px;
  810. padding: 0 20px 18px;
  811. color: #333;
  812. font-size: 14px;
  813. flex-wrap: wrap;
  814. }
  815. .info-item {
  816. white-space: nowrap;
  817. }
  818. /* 文本溢出省略样式(深度探索) */
  819. .ellipsis-text {
  820. display: inline-block;
  821. width: 100%;
  822. white-space: nowrap;
  823. overflow: hidden;
  824. text-overflow: ellipsis;
  825. vertical-align: middle;
  826. }
  827. /* 开通/编辑指标复选(深度探索) */
  828. .indicator-checkbox-group {
  829. display: flex;
  830. flex-wrap: wrap;
  831. gap: 8px;
  832. margin-top: 8px;
  833. width: 100%
  834. }
  835. .indicator-checkbox-item {
  836. flex: 0 0 calc(20% - 5px);
  837. box-sizing: border-box;
  838. padding: 4px 0;
  839. }
  840. :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
  841. background-color: #ff0000 !important;
  842. border-color: #ff0000 !important;
  843. }
  844. :deep(.el-checkbox__input.is-checked .el-checkbox__inner::after) {
  845. border-color: #fff !important;
  846. }
  847. :deep(.el-checkbox__input:hover .el-checkbox__inner) {
  848. border-color: #ff0000 !important;
  849. }
  850. :deep(.el-checkbox__input:focus .el-checkbox__inner) {
  851. box-shadow: 0 0 0 2px rgba(255, 0, 0, 0.2) !important;
  852. }
  853. :deep(.el-checkbox__label) {
  854. color: #333 !important;
  855. font-size: 14px !important;
  856. }
  857. /* 权限详情(深度探索) */
  858. .permission-detail-dialog {
  859. --el-dialog-padding-primary: 15px;
  860. }
  861. .detail-container {
  862. background-color: #fff1f0;
  863. border-radius: 6px;
  864. padding: 15px;
  865. }
  866. .hlid-item {
  867. margin-bottom: 25px;
  868. }
  869. .label {
  870. color: #666;
  871. font-weight: 500;
  872. }
  873. .value {
  874. color: #333;
  875. }
  876. .expire-section {
  877. margin-top: 10px;
  878. }
  879. .section-title {
  880. font-size: 16px;
  881. color: #333;
  882. margin-bottom: 10px;
  883. font-weight: bold;
  884. }
  885. .indicator-list {
  886. display: flex;
  887. flex-direction: column;
  888. gap: 8px;
  889. }
  890. .indicator-item {
  891. padding: 6px 0;
  892. display: flex;
  893. align-items: center;
  894. }
  895. .indicator-name {
  896. color: #666;
  897. font-size: 14px;
  898. }
  899. .expire-time {
  900. color: #333;
  901. font-size: 14px;
  902. margin-left: 8px;
  903. }
  904. .expired-tag {
  905. background-color: #ffccd5;
  906. color: #f56c6c;
  907. font-size: 12px;
  908. padding: 2px 8px;
  909. border-radius: 4px;
  910. margin-left: 8px;
  911. }
  912. </style>