Browse Source

深度探索-主页面完成

milestone-20251117-DeepChart后台一期
liruiqiang 2 months ago
parent
commit
80fb505ded
  1. 20
      src/api/userPermissions.js
  2. 11
      src/views/UserPermissions/Market.vue
  3. 834
      src/views/UserPermissions/Module.vue

20
src/api/userPermissions.js

@ -117,4 +117,22 @@ export function exitDEApi(params) {
method: "post",
data: params,
});
}
}
// 深度探索-权限详情
export function detailDEApi(params) {
return request({
url: base_url + "/admin/deepExploration/detail",
method: "post",
data: params,
});
}
// 深度探索-指标列表
export function indicatorListApi(params) {
return request({
url: base_url + "/admin/indicator/list",
method: "post",
data: params,
});
}

11
src/views/UserPermissions/Market.vue

@ -279,18 +279,25 @@ const checkHlids = () => {
const checkTime = () => {
if (timeType.value === 'expire') {
//
//
if (!expireTime.value) {
ElMessage.error('请选择到期时间');
return false;
}
} else if (timeType.value === 'delay') {
//
//
if (!delayValue.value || !delayUnit.value) {
ElMessage.error('延期时间必须填写完整(数值+单位)');
return false;
}
const delayNum = Number(delayValue.value);
if (isNaN(delayNum) || delayNum < 0) {
ElMessage.error('延期时间不能为负数,请输入有效正数');
return false;
}
if (delayNum === 0) {
ElMessage.error('延期时间不能为0,请输入有效正数');
return false;
}
} else {
ElMessage.error('请设置权限时间');
return false;

834
src/views/UserPermissions/Module.vue

@ -169,13 +169,296 @@
</div>
</el-dialog>
</div>
<div class="page-container" v-show="taber == 'DeepExplore'">
<!-- 搜索区域 -->
<div class="search-containerDE">
<!-- 输入项区域 -->
<div class="search-formDE">
<div class="search-itemDE">
<span class="form-labelDE">账号</span>
<el-input
v-model="searchFormDE.dccode"
placeholder="请输入账号"
clearable
style="height: 36px; width: 140px;"
/>
</div>
<div class="search-itemDE">
<span class="form-labelDE">姓名</span>
<el-input
v-model="searchFormDE.dcname"
placeholder="请输入姓名"
clearable
style="height: 36px; width: 180px;"
/>
</div>
<div class="search-itemDE">
<span class="form-labelDE">客户类型</span>
<el-select
v-model="searchFormDE.user_role"
placeholder="请选择客户类型"
clearable
style="height: 36px; width: 160px;"
>
<el-option label="非网" value="2" />
<el-option label="会员" value="1" />
</el-select>
</div>
<div class="search-itemDE">
<span class="form-labelDE">地区</span>
<el-select
v-model="searchFormDE.market"
placeholder="请选择地区"
clearable
style="height: 36px; width: 160px;"
:loading="isRegionLoading"
>
<el-option
v-for="region in regionList"
:key="region.id"
:label="region.text_cn"
:value="region.market"
/>
</el-select>
</div>
<div class="search-itemDE">
<span class="form-labelDE">指标名称</span>
<el-select
v-model="searchFormDE.indicator_id"
placeholder="请选择指标名称"
clearable
style="height: 36px; width: 160px;"
>
<el-option
v-for="item in indicatorOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</div>
</div>
<!-- 按钮组 -->
<div class="button-groupDE">
<el-button type="primary" @click="searchDE">搜索</el-button>
<el-button type="danger" @click="enableAccessDE">开通权限</el-button>
<el-button type="success" @click="exportExcelDE">导出Excel列表</el-button>
<el-button color="#626aef" @click="exportListDE">查看导出列表</el-button>
<el-button type="primary" @click="resetBnDE">重置</el-button>
</div>
</div>
<!-- tab切换 -->
<div class="tab-group">
<button
class="tab-btn"
:class="{ active: taber === 'DeepMate' }"
@click="taber = 'DeepMate'"
>
DeepMate
</button>
<button
class="tab-btn"
:class="{ active: taber === 'DeepExplore' }"
@click="taber = 'DeepExplore'"
>
深度探索
</button>
</div>
<!-- 数据 -->
<el-table
:data="tableDataDE"
style="width: 100%; margin-top: 20px;"
header-cell-class-name="table-header"
@sort-change="handleSortChangeDE"
:default-sort="{ prop: null, order: null }"
class="table-rounded"
:loading="tableLoadingDE"
>
<el-table-column prop="id" label="序号" align="center" header-align="center" width="60">
<template #default="scope">
{{ (currentPageDE - 1) * pageSizeDE + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="dccode" label="账号" align="center" header-align="center"/>
<el-table-column prop="dcname" label="姓名" align="center" header-align="center"/>
<el-table-column prop="name" label="指标名称" align="center" header-align="center" width="200">
<template #default="scope">
<el-tooltip
effect="dark"
:content="scope.row.name"
placement="top"
>
<span class="ellipsis-text">{{ scope.row.name }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="created_at" label="开通时间" align="center" header-align="center" sortable="custom" width="200"/>
<el-table-column prop="expire_time" label="到期时间" align="center" header-align="center" sortable="custom" width="200"/>
<el-table-column label="操作" align="center" header-align="center">
<template #default="scope">
<el-button type="text" @click="handleEditDE(scope.row)">编辑</el-button>
<el-button type="text" @click="handleDetailsDE(scope.row.dccode)">权限详情</el-button>
<el-button type="text" @click="handleLogDE(scope.row.dccode)">操作日志</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="demo-pagination-block">
<el-pagination
@size-change="handleSizeChangeDE"
@current-change="handleCurrentChangeDE"
:current-page="currentPageDE"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSizeDE"
layout="total, sizes, prev, pager, next, jumper"
:total= "datatotalDE"
/>
</div>
<!-- 开通/编辑 -->
<el-dialog v-model="dialogVisibleDE" :title="addOrUpdataDE === 1 ? '添加权限' : '设置'" width="550px" :before-close="cancelDE">
<!-- 设置用户 -->
<div class="form-item" v-if="addOrUpdataDE === 1">
<label class="form-label">设置用户</label>
<el-input type="textarea" v-model="hlidsInputDE" rows=10
placeholder="请输入HLid...
示例
90048004
90048005
90048006"
/>
<div class="tip">支持批量输入每次最多1000个手动/Excel粘贴均可</div>
</div>
<!-- 编辑回显 -->
<div class="info-container" v-if="addOrUpdataDE === 0">
<span class="info-item">HLid{{ hlidsInputDE }}</span>
<span class="info-item">当前到期时间{{ deadline.split(' ')[0] }}</span>
</div>
<!-- 设置指标 -->
<div class="form-item">
<label class="form-label">选择指标</label>
<el-checkbox-group v-model="indicator_id" class="indicator-checkbox-group">
<el-checkbox
v-for="item in indicatorOptions"
:key="item.id"
:label="item.id"
class="indicator-checkbox-item"
>
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div>
<!-- 设置权限时间 -->
<div class="form-item">
<label class="form-label">设置权限时间</label>
<el-radio-group v-model="timeType" class="radio-group">
<el-radio label="expire" class="radio-item">
<span>到期时间</span>
<el-date-picker
v-model="expireTime"
type="date"
placeholder="请选择到期日期"
:disabled-date="disabledDate"
style="width: 220px; margin-left: 8px;"
/>
</el-radio>
<el-radio label="delay" class="radio-item">
<span>延期时间</span>
<el-input
v-model.number="delayValue"
type="number"
style="width: 60px; margin: 0 8px;"
placeholder="1"
@input="handleDelayInput"
/>
<el-select v-model="delayUnit" placeholder="请选择" style="width: 150px;">
<el-option label="年" value="year"></el-option>
<el-option label="月" value="month"></el-option>
<el-option label="周" value="week"></el-option>
<el-option label="日" value="day"></el-option>
</el-select>
</el-radio>
</el-radio-group>
</div>
<!-- 备注-->
<div class="form-item inline-form-item">
<label class="form-label">备注</label>
<el-input
type="textarea"
v-model="remark"
rows=3
placeholder="请输入备注..."
maxlength="150"
show-word-limit
/>
</div>
<!-- 操作人 -->
<div class="form-item inline-form-item">
<label class="form-label">操作人</label>
<el-input v-model="operator" placeholder="请填写操作人"/>
</div>
<!-- 按钮区域 -->
<div class="dialog-footer">
<el-button type="default" plain @click="cancelDE">取消</el-button>
<el-button type="primary" @click="submitFormDE" style="background-color: #ff0000; border-color: #ff0000;">提交</el-button>
</div>
</el-dialog>
<!-- 权限详情 -->
<el-dialog
v-model="showPermissionDetail"
title="权限详情"
width="400px"
:close-on-click-modal="false"
:show-close="true"
class="permission-detail-dialog"
>
<div class="detail-container">
<!-- HLid 信息 -->
<div class="hlid-item">
<span class="label">HLid</span>
<span class="value">{{ HLid }}</span>
</div>
<!-- 到期时间区域 -->
<div class="expire-section">
<h3 class="section-title">到期时间</h3>
<div class="indicator-list">
<div
v-for="(item, index) in permissionData"
:key="index"
class="indicator-item"
>
<span class="indicator-name">{{ item.name }}</span>
<template v-if="item.is_expired === 1">
<span class="expired-tag">已到期</span>
</template>
<template v-else>
<span class="expire-time">{{ item.expire_time.split(' ')[0] }}</span>
</template>
</div>
</div>
</div>
</div>
</el-dialog>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ref, reactive, onMounted, computed } from 'vue';
import { ElMessage } from 'element-plus';
import { marketListApi, userDMListApi, exportDeepMateApi, exitDMApi } from '../../api/userPermissions'
import { marketListApi, indicatorListApi, userDMListApi, exportDeepMateApi, exitDMApi, userDEListApi, exportDeepExploreApi, exitDEApi, detailDEApi } from '../../api/userPermissions'
import router from '../../router';
import { useRoute } from 'vue-router';
@ -195,7 +478,9 @@ onMounted(() => {
taber.value = TaberValues.includes(String(taberQuery)) ? String(taberQuery) : "DeepMate";
fetchRegionList();
indicatorList();
DMTableData();
DETableData();
});
//
@ -329,14 +614,14 @@ const exportListDM = () => {
});
};
//
// DeepMate
const handleEditDM = (row) => {
dialogVisibleDM.value = true;
hlidsInput.value = row.dccode;
deadtoken.value = row.token_num;
};
//
// DeepMate
const handleLogDM = (dccode) => {
router.push({
path: "/userPermissions/logDeepMate",
@ -417,7 +702,7 @@ const checkTokenNum = () => {
return true;
};
//
// DeepMate
const submitFormDM = async () => {
//
if (!checkHlids() || !checkTokenNum()) {
@ -465,6 +750,374 @@ const resetFormDM = () => {
hlidsInput.value = '';
token_num.value = '';
};
//
const indicatorOptions = ref([]);
const indicatorList = async () => {
try {
const data = await indicatorListApi({token: token});
indicatorOptions.value = data.list;
} catch (error) {
console.error('获取指标列表失败:', error);
indicatorOptions.value = [];
}
}
//
const searchFormDE = reactive({
dccode: '',
dcname: '',
market: '',
user_role: '',
indicator_id: ''
});
//
const sortPropDE = ref(null);
const sortOrderDE = ref(null);
//
const currentPageDE = ref(1);
const pageSizeDE = ref(10);
//
const tableDataDE = ref([]);
const tableLoadingDE = ref(false);
const datatotalDE = ref(0)
//
const handleSizeChangeDE = (val) => {
pageSizeDE.value = val;
DETableData();
console.log(`每页 ${val}`);
};
const handleCurrentChangeDE = (val) => {
currentPageDE.value = val;
DETableData();
console.log(`当前页: ${val}`);
};
//
const handleSortChangeDE = (sort) => {
const { prop, order } = sort;
if (!['created_at', 'expire_time'].includes(prop)) return;
sortPropDE.value = prop; //
sortOrderDE.value = order; //
DETableData();
};
//
const DETableData = async () => {
try {
tableLoadingDE.value = true;
const requestParams = {
token: token,
dccode: searchFormDE.dccode,
dcname: searchFormDE.dcname,
market: searchFormDE.market,
user_role: searchFormDE.user_role,
indicator_id: searchFormDE.indicator_id,
sort_field: sortPropDE.value,
sort_order: sortOrderDE.value,
page: currentPageDE.value,
page_size: pageSizeDE.value
};
const data = await userDEListApi(requestParams);
tableDataDE.value = data.list
datatotalDE.value = data.total
} catch (error) {
console.error('获取表格数据失败:', error);
tableDataDE.value = [];
datatotalDE.value = 0
} finally {
tableLoadingDE.value = false;
}
};
//
const searchDE = () => {
currentPageDE.value = 1;
DETableData();
};
//
const resetBnDE = () => {
searchFormDE.dccode = '';
searchFormDE.dcname = '';
searchFormDE.market = '';
searchFormDE.user_role = '';
searchFormDE.indicator_id = '';
sortPropDE.value = null;
sortOrderDE.value = null;
currentPageDE.value = 1;
pageSizeDE.value = 10;
DETableData();
};
// Excel
const exportExcelDE = async () => {
const requestParams = {
token: token,
dccode: searchFormDE.dccode,
dcname: searchFormDE.dcname,
market: searchFormDE.market,
user_role: searchFormDE.user_role,
indicator_id: searchFormDE.indicator_id,
sort_field: sortPropDE.value,
sort_order: sortOrderDE.value
};
const data = await exportDeepExploreApi(requestParams);
if (data != '') {
ElMessage.success('已导出');
}
};
//
const exportListDE = () => {
router.push({
path: "/userPermissions/export"
});
};
//
const enableAccessDE = () => {
dialogVisibleDE.value = true;
addOrUpdataDE.value = 1;
};
//
const handleEditDE = (row) => {
dialogVisibleDE.value = true;
hlidsInputDE.value = row.dccode;
deadline.value = row.expire_time;
};
//
const handleDetailsDE = (dccode) =>{
openDetail(dccode)
}
//
const handleLogDE = (dccode) => {
router.push({
path: "/userPermissions/logDeepExplore",
query: { dccode: dccode }
});
};
//
const dialogVisibleDE = ref(false);
//
const hlidsInputDE = ref('');
const indicator_id = ref([]);
const timeType = ref('');
const expireTime = ref('');
const delayValue = ref('');
const delayUnit = ref('');
const remark = ref('');
const operator = ref('');
//
const addOrUpdataDE = ref(0);
//
const deadline = ref('');
//
const indicatorStr = computed(() => {
return indicator_id.value?.join('、') || '';
});
// 0
const disabledDate = (time) => {
return time.getTime() < new Date().getTime() - 8.64e7;
};
//
const formatDate = (date) => {
if (!date) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}/${month}/${day}`;
};
//
const handleDelayInput = () => {
if (delayValue.value !== null && delayValue.value !== undefined) {
delayValue.value = Math.floor(delayValue.value);
}
};
// HLid
const checkHlidsDE = () => {
//
if (!hlidsInputDE.value.trim()) {
ElMessage.error('请输入HLid');
return false;
}
//
const hlidList = hlidsInputDE.value.split('\n')
.map(item => item.trim())
.filter(item => item)
.filter((item, index, self) => self.indexOf(item) === index); //
// 1000
if (hlidList.length > 1000) {
ElMessage.error('HLid数量不能超过1000个');
return false;
}
// 8
const hlidReg = /^\d{8}$/;
for (const hlid of hlidList) {
if (!hlidReg.test(hlid)) {
ElMessage.error(`有HLid格式错误:${hlid},请重新输入`);
return false;
}
}
return true;
};
//
const checkmodel = () => {
if (indicator_id.value.length === 0) {
ElMessage.error('请至少选择一个指标');
return false;
}
return true;
};
//
const checkTime = () => {
if (timeType.value === 'expire') {
//
if (!expireTime.value) {
ElMessage.error('请选择到期时间');
return false;
}
} else if (timeType.value === 'delay') {
//
if (!delayValue.value || !delayUnit.value) {
ElMessage.error('延期时间必须填写完整(数值+单位)');
return false;
}
const delayNum = Number(delayValue.value);
if (isNaN(delayNum) || delayNum < 0) {
ElMessage.error('延期时间不能为负数,请输入有效正数');
return false;
}
if (delayNum === 0) {
ElMessage.error('延期时间不能为0,请输入有效正数');
return false;
}
} else {
ElMessage.error('请设置权限时间');
return false;
}
return true;
};
//
const checkRemark = () => {
if (!remark.value.trim()) {
ElMessage.error('请输入备注');
return false;
}
return true;
};
//
const submitFormDE = async () => {
//
if (!checkHlidsDE() || !checkmodel() || !checkTime() || !checkRemark()) {
return;
}
try {
//
const requestParams = {
token: token,
// HLid
hlids: hlidsInputDE.value.split('\n')
.map(item => item.trim())
.filter(item => item)
.join('\n'),
//
indicator_id: indicatorStr.value,
//
remark: remark.value.trim(),
//
...(operator.value.trim() && { operator: operator.value.trim() }),
//
...(timeType.value === 'expire'
? { expire_time: formatDate(expireTime.value) }
: {
[delayUnit.value]: Number(delayValue.value)
})
};
console.log('传给后端的参数:', requestParams);
//
await exitDEApi(requestParams);
ElMessage.success(addOrUpdataDM.value === 1 ? '成功添加用户权限' : '成功修改用户权限');
//
resetForm();
dialogVisibleDE.value = false;
addOrUpdataDE.value = 0;
//
DETableData();
} catch (error) {
ElMessage.error('添加权限失败,请重试');
}
};
//
const resetForm = () => {
hlidsInputDE.value = '';
indicator_id.value = [];
timeType.value = '';
expireTime.value = '';
delayValue.value = '';
delayUnit.value = '';
remark.value = '';
operator.value = '';
};
//
const cancelDE = () => {
resetForm();
dialogVisibleDE.value = false;
addOrUpdataDE.value = 0;
};
//
const showPermissionDetail = ref(false);
//
const HLid = ref('');
const permissionData = ref([]);
//
const openDetail = async(dccode) => {
HLid.value = dccode
//
const res = await detailDEApi({
token: token,
dccode: dccode
})
permissionData.value = res
//
showPermissionDetail.value = true;
};
</script>
<style scoped>
@ -679,4 +1332,175 @@ const resetFormDM = () => {
.tab-btn:not(.active):hover {
background-color: #fff5f5;
}
/* 搜索区域(深度探索) */
.search-containerDE {
display: flex;
height: auto;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 12px;
align-self: stretch;
border-radius: 8px;
background: #FEFAF9;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
padding: 15px;
margin-bottom: 20px;
}
/* 搜索表单(深度探索) */
.search-formDE {
display: flex;
align-items: center;
width: 100%;
gap: 15px;
flex-wrap: wrap;
row-gap: 8px;
}
/* 单个搜索项(深度探索) */
.search-itemDE {
display: flex;
align-items: center;
gap: 6px;
}
/* 搜索标签文字(深度探索) */
.form-labelDE {
font-weight: 800 !important;
font-size: 15px;
text-align: left;
color: #333;
margin-top: 0;
}
/* 按钮组(深度探索) */
.button-groupDE {
display: flex;
align-items: center;
gap: 10px !important;
}
/* 按钮样式(深度探索) */
.button-groupDE .el-button {
padding: 6px 10px !important;
font-size: 14px !important;
height: 36px !important;
}
/* 文本溢出省略样式(深度探索) */
.ellipsis-text {
display: inline-block;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
/* 开通/编辑指标复选(深度探索) */
.indicator-checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
width: 100%
}
.indicator-checkbox-item {
flex: 0 0 calc(20% - 5px);
box-sizing: border-box;
padding: 4px 0;
}
:deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
background-color: #ff0000 !important;
border-color: #ff0000 !important;
}
:deep(.el-checkbox__input.is-checked .el-checkbox__inner::after) {
border-color: #fff !important;
}
:deep(.el-checkbox__input:hover .el-checkbox__inner) {
border-color: #ff0000 !important;
}
:deep(.el-checkbox__input:focus .el-checkbox__inner) {
box-shadow: 0 0 0 2px rgba(255, 0, 0, 0.2) !important;
}
:deep(.el-checkbox__label) {
color: #333 !important;
font-size: 14px !important;
}
/* 权限详情(深度探索) */
.permission-detail-dialog {
--el-dialog-padding-primary: 15px;
}
.detail-container {
background-color: #fff1f0;
border-radius: 6px;
padding: 15px;
}
.hlid-item {
margin-bottom: 25px;
}
.label {
color: #666;
font-weight: 500;
}
.value {
color: #333;
}
.expire-section {
margin-top: 10px;
}
.section-title {
font-size: 16px;
color: #333;
margin-bottom: 10px;
font-weight: bold;
}
.indicator-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.indicator-item {
padding: 6px 0;
display: flex;
align-items: center;
}
.indicator-name {
color: #666;
font-size: 14px;
}
.expire-time {
color: #333;
font-size: 14px;
margin-left: 8px;
}
.expired-tag {
background-color: #ffccd5;
color: #f56c6c;
font-size: 12px;
padding: 2px 8px;
border-radius: 4px;
margin-left: 8px;
}
</style>
Loading…
Cancel
Save