Browse Source

新建期限管理;将deepmate、深度探索和行情期限改名并放入期限管理;注释原本的左侧导航栏页面;

songjie/feature-20260331101525-后台整改需求
songjie 2 weeks ago
parent
commit
0317820459
  1. 50
      src/router/index.js
  2. 827
      src/views/UserPermissions/MarketTerm.vue
  3. 1021
      src/views/UserPermissions/TemplateLimit.vue
  4. 733
      src/views/UserPermissions/TokenManage.vue

50
src/router/index.js

@ -28,24 +28,50 @@ const routes = [
name: 'userPermissions',
meta: { title: '用户权限管理', icon: "UserFilled", showSidebar: true, isParentNav: true },
children: [
{
path: 'market',
name: 'market',
component: () => import('../views/UserPermissions/Market.vue'),
meta: { title: '行情期限', showSidebar: true }
},
{
path: 'module',
name: 'module',
component: () => import('../views/UserPermissions/Module.vue'),
meta: { title: '模块期限', showSidebar: true }
},
// {
// path: 'market',
// name: 'market',
// component: () => import('../views/UserPermissions/Market.vue'),
// meta: { title: '行情期限', showSidebar: true }
// },
// {
// path: 'module',
// name: 'module',
// component: () => import('../views/UserPermissions/Module.vue'),
// meta: { title: '模块期限', showSidebar: true }
// },
{
path: 'invitedLook',
name: 'invitedLook',
component: () => import('../views/UserPermissions/invitedLook.vue'),
meta: { title: '查看被邀请用户', showSidebar: true }
},
// 期限管理子菜单
{
path: 'limitManagement',
name: 'limitManagement',
meta: { title: '期限管理', showSidebar: true },
children: [
{
path: 'tokenManage',
name: 'tokenManage',
component: () => import('../views/UserPermissions/TokenManage.vue'),
meta: { title: 'Token管理', showSidebar: true }
},
{
path: 'templateLimit',
name: 'templateLimit',
component: () => import('../views/UserPermissions/TemplateLimit.vue'),
meta: { title: '模版期限', showSidebar: true }
},
{
path: 'marketTerm',
name: 'marketTerm',
component: () => import('../views/UserPermissions/MarketTerm.vue'),
meta: { title: '行情期限', showSidebar: true }
}
]
},
// 深度探索--操作日志
{
path: 'logDeepexplore',

827
src/views/UserPermissions/MarketTerm.vue

@ -0,0 +1,827 @@
<template>
<div class="page-container">
<!-- 搜索区域 -->
<div class="search-container">
<div class="search-form">
<div class="search-group">
<div class="search-group1">
<div class="search-item">
<span class="form-label">账号</span>
<el-input
v-model="searchForm.dccode"
placeholder="请输入账号"
clearable
style="height: 36px; width: 140px;"
/>
</div>
<div class="search-item">
<span class="form-label">姓名</span>
<el-input
v-model="searchForm.dcname"
placeholder="请输入姓名"
clearable
style="height: 36px; width: 140px;"
/>
</div>
<!-- <div class="search-item">
<span class="form-label">来源</span>
<el-select v-model="searchForm.origin_id" placeholder="请选择来源" clearable filterable style="height: 36px; width: 160px" :loading="isOriginLoading">
<el-option v-for="origin in originList" :key="origin.origin_id" :label="origin.origin_name" :value="origin.origin_id" />
</el-select>
</div> -->
<div class="search-item">
<span class="form-label">地区</span>
<el-select
v-model="searchForm.market"
placeholder="请选择地区"
clearable
filterable
style="height: 36px; width: 160px;"
:loading="isRegionLoading"
>
<el-option
v-for="region in regionList"
:key="region.ID"
:label="region.Name"
:value="region.ID"
/>
</el-select>
</div>
</div>
<div class="search-group2">
<!-- <div class="search-item">
<span class="form-label">注册方式</span>
<el-input
v-model="searchForm.register_type"
placeholder="请输入手机号/邮箱"
clearable
style="height: 36px; width: 220px;"
/>
</div> -->
<div class="search-item">
<span class="form-label">注册时间</span>
<el-date-picker v-model="searchDate" type="datetimerange" :shortcuts="shortcuts" range-separator="" start-placeholder="开始时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" />
</div>
</div>
</div>
<div class="button-group">
<el-button type="primary" @click="search">搜索</el-button>
<el-button type="danger" @click="enableAccess">开通权限</el-button>
<el-button type="success" @click="exportExcel">导出Excel列表</el-button>
<el-button color="#626aef" @click="exportList">查看导出列表</el-button>
<el-button type="primary" @click="resetBn">重置</el-button>
</div>
</div>
</div>
<!-- 数据 -->
<el-table
:data="tableData"
style="width: 100%; margin-top: 20px;"
header-cell-class-name="table-header"
@sort-change="handleSortChange"
:default-sort="{ prop: null, order: null }"
class="table-rounded"
:loading="tableLoading"
>
<el-table-column prop="id" label="序号" align="center" header-align="center" width="80">
<template #default="scope">
{{ (currentPage - 1) * pageSize + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="jwcode" label="账号" align="center" header-align="center" width="120"/>
<el-table-column prop="username" label="姓名" align="center" header-align="center" width="150"/>
<!-- <el-table-column prop="origin_name" label="来源" align="center" header-align="center" width="200"/> -->
<el-table-column prop="country" label="地区" align="center" header-align="center" width="150"/>
<!-- <el-table-column prop="dialingCode" label="手机区号" align="center" header-align="center" width="80"/> -->
<!-- <el-table-column prop="mobiles" label="手机号" align="center" header-align="center" width="200"/> -->
<!-- <el-table-column prop="emails" label="邮箱" align="center" header-align="center" width="200"/> -->
<!-- <el-table-column prop="emails" label="邮箱" align="center" header-align="center" width="150">
<template #default="scope">
<el-tooltip
effect="dark"
:content="scope.row.emails"
placement="top"
>
<span class="ellipsis-text">{{ scope.row.emails }}</span>
</el-tooltip>
</template>
</el-table-column> -->
<el-table-column prop="regtime" 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="操作" width="180" align="center" header-align="center" fixed="right">
<template #default="scope">
<el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="text" @click="handleLog(scope.row.jwcode)">操作日志</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="demo-pagination-block">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total= "datatotal"
/>
</div>
<el-dialog v-model="dialogVisible" :title="addOrUpdata === 1 ? '添加权限' : '设置'" width="500px" :before-close="cancel">
<!-- 设置用户 -->
<div class="form-item" v-if="addOrUpdata === 1">
<label class="form-label">设置用户</label>
<el-input type="textarea" v-model="hlidsInput" rows=10
placeholder="请输入HLid...
示例
90048004
90048005
90048006"
/>
<div class="tip">支持批量输入每次最多1000个手动/Excel粘贴均可</div>
</div>
<!-- 编辑回显 -->
<div class="info-container" v-if="addOrUpdata === 0">
<span class="info-item">Homily ID{{ hlidsInput }}</span>
<span class="info-item">当前到期时间{{ deadline.split(' ')[0] }}</span>
</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="cancel">取消</el-button>
<el-button type="primary" @click="submitForm" style="background-color: #ff0000; border-color: #ff0000;">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { marketListApi, userMListApi, exportMarketApi, exitMApi } from '../../api/userPermissions'
import router from '../../router';
// token
const token = localStorage.getItem('token')
//
const searchForm = reactive({
dccode: '',
dcname: '',
origin_id: "",
market: '',
register_type: ''
});
const searchDate = ref([]);
//
const sortProp = ref(null);
const sortOrder = ref(null);
//
const tableData = ref([]);
const tableLoading = ref(false);
const datatotal = ref(0)
//
const currentPage = ref(1);
const pageSize = ref(10);
//
const regionList = ref([]);
const isRegionLoading = ref(false);
//
const originList = ref([]);
const isOriginLoading = ref(false);
//
const dialogVisible = ref(false);
//
const hlidsInput = ref('');
const timeType = ref('');
const expireTime = ref('');
const delayValue = ref('');
const delayUnit = ref('');
const remark = ref('');
const operator = ref('');
//
const addOrUpdata = ref(0);
//
const deadline = ref('');
// 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}`;
};
// HLid
const checkHlids = () => {
//
if (!hlidsInput.value.trim()) {
ElMessage.error('请输入HLid');
return false;
}
//
const hlidList = hlidsInput.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 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 handleDelayInput = () => {
if (delayValue.value !== null && delayValue.value !== undefined) {
delayValue.value = Math.floor(delayValue.value);
}
};
//
const checkRemark = () => {
if (!remark.value.trim()) {
ElMessage.error('请输入备注');
return false;
}
return true;
};
//
const Noshake = ref(false)
//
const submitForm = async () => {
//
if (Noshake.value) return;
Noshake.value = true;
//
if (!checkHlids() || !checkTime() || !checkRemark()) {
Noshake.value = false;
return;
}
try {
//
const requestParams = {
token: token,
// HLid
hlids: hlidsInput.value.split('\n')
.map(item => item.trim())
.filter(item => item)
.join('\n'),
//
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);
//
const res = await exitMApi(requestParams);
ElMessage.success('成功添加用户权限');
//
resetForm();
dialogVisible.value = false;
addOrUpdata.value = 0;
//
fetchTableData();
} catch (error) {
ElMessage.error('添加权限失败,请重试');
} finally {
Noshake.value = false;
}
};
//
const cancel = () => {
resetForm();
dialogVisible.value = false;
addOrUpdata.value = 0;
};
//
const resetForm = () => {
hlidsInput.value = '';
timeType.value = '';
expireTime.value = '';
delayValue.value = '';
delayUnit.value = '';
remark.value = '';
operator.value = '';
};
//
const fetchRegionList = async () => {
try {
isRegionLoading.value = true;
const data = await marketListApi({
token: token,
app_form: "en"
});
regionList.value = data.list;
} catch (error) {
console.error('获取地区列表失败:', error);
regionList.value = [];
} finally {
isRegionLoading.value = false;
}
};
//
const fetchTableData = async () => {
try {
tableLoading.value = true;
const requestParams = {
token: token,
dccode: searchForm.dccode,
dcname: searchForm.dcname,
origin_id: searchForm.origin_id,
market: searchForm.market,
register_type: searchForm.register_type,
start_time: searchDate.value && searchDate.value[0] ? searchDate.value[0] : "",
end_time: searchDate.value && searchDate.value[1] ? searchDate.value[1] : "",
sort_field: sortProp.value,
sort_order: sortOrder.value,
page: currentPage.value,
page_size: pageSize.value
};
const data = await userMListApi(requestParams);
tableData.value = data.list
datatotal.value = data.total
} catch (error) {
console.error('获取表格数据失败:', error);
tableData.value = [];
datatotal.value = 0
} finally {
tableLoading.value = false;
}
};
// +
onMounted(() => {
fetchRegionList();
fetchTableData();
});
//
const search = () => {
currentPage.value = 1;
fetchTableData();
};
//
const enableAccess = () => {
dialogVisible.value = true;
addOrUpdata.value = 1;
};
// Excel
const exportExcel = async () => {
const requestParams = {
token: token,
dccode: searchForm.dccode,
dcname: searchForm.dcname,
origin_id: searchForm.origin_id,
market: searchForm.market,
register_type: searchForm.register_type,
start_time: searchDate.value && searchDate.value[0] ? searchDate.value[0] : "",
end_time: searchDate.value && searchDate.value[1] ? searchDate.value[1] : "",
sort_field: sortProp.value,
sort_order: sortOrder.value
};
const data = await exportMarketApi(requestParams);
if (data != '') {
ElMessage.success('已导出');
}
};
//
const exportList = () => {
router.push({
path: "/userPermissions/export"
});
};
//
const resetBn = () => {
searchForm.dccode = '';
searchForm.dcname = '';
searchForm.origin_id = '';
searchForm.market = '';
searchForm.register_type = '';
searchDate.value = [];
sortProp.value = null;
sortOrder.value = null;
currentPage.value = 1;
pageSize.value = 10;
fetchTableData();
};
//
const handleEdit = (row) => {
dialogVisible.value = true;
hlidsInput.value = row.jwcode;
deadline.value = row.expire_time;
};
//
const handleLog = (jwcode) => {
router.push({
path: "/userPermissions/logMarket",
query: { dccode: jwcode }
});
};
//
const handleSizeChange = (val) => {
pageSize.value = val;
fetchTableData();
console.log(`每页 ${val}`);
};
const handleCurrentChange = (val) => {
currentPage.value = val;
fetchTableData();
console.log(`当前页: ${val}`);
};
//
const handleSortChange = (sort) => {
const { prop, order } = sort;
//
if (!['regtime', 'expire_time'].includes(prop)) return;
//
sortProp.value = prop; //
sortOrder.value = order; //
fetchTableData();
// console.log(`${sortProp.value}${sortOrder.value}`);
};
//
const shortcuts = [
{
text: '最近一周',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
return [start, end]
},
},
{
text: '最近一个月',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
return [start, end]
},
},
{
text: '最近三个月',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
return [start, end]
},
},
]
</script>
<style scoped>
/* 父容器 */
.page-container {
position: relative;
min-height: 600px;
}
/* 搜索区域 */
.search-container {
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-form {
display: flex;
align-items: center;
width: 100%;
gap: 15px;
flex-wrap: wrap;
row-gap: 8px;
}
/* 搜索组 */
.search-group {
}
.search-group1{
display: flex;
align-items: center;
gap: 15px;
}
.search-group2{
display: flex;
margin-top: 15px;
align-items: center;
gap: 15px;
}
/* 单个搜索项 */
.search-item {
display: flex;
align-items: center;
gap: 6px;
}
/* 搜索标签文字 */
.form-label {
font-weight: 800 !important;
font-size: 15px;
text-align: left;
color: #333;
margin-top: 13px;
font-family: "SimHei", "Heiti SC", "Microsoft YaHei", sans-serif !important;
}
/* 按钮组 */
.button-group {
display: flex;
align-items: center;
gap: 0px !important;
margin-left: auto;
}
/* 按钮样式 */
.button-group .el-button {
padding: 6px 10px !important;
font-size: 14px !important;
height: 36px !important;
}
/* 表格样式 */
.table-rounded {
border-radius: 12px !important;
overflow: hidden !important;
border: 1px solid #e4e7ed !important;
height: 700px;
}
.table-header {
text-align: center !important;
font-weight: 800 !important;
font-size: 15px !important;
color: #333 !important;
background-color: #f8f9fa !important;
}
.el-table__cell {
border-right: none !important;
border-bottom: 1px solid #e4e7ed !important;
}
.el-table__header th.el-table__cell {
border-right: none !important;
border-bottom: 1px solid #e4e7ed !important;
}
.el-table__row:hover .el-table__cell {
background-color: #fafafa !important;
}
.ellipsis-text {
display: inline-block;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
/* 分页组件样式 */
.demo-pagination-block {
display: flex;
width: 100%;
height: 44px;
padding: 0 16px;
align-items: center;
gap: 16px;
position: absolute;
margin-top: 10px;
border-radius: 0 0 3px 3px;
border-top: 1px solid #EAEAEA;
background: #FEFBFB;
box-sizing: border-box;
}
/* 添加/修改样式 */
.form-item {
margin-bottom: 24px;
padding-left: 20px;
padding-right: 20px;
text-align: left;
}
.form-label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.radio-group {
display: flex;
flex-direction: column;
gap: 12px;
align-items: flex-start;
}
.radio-item {
display: flex;
align-items: center;
}
.radio-item span {
margin-right: 8px;
}
.tip {
font-size: 12px;
color: #909399;
margin-top: 4px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 20px;
}
.inline-form-item {
display: flex;
align-items: flex-start;
gap: 12px;
}
.inline-form-item .form-label {
display: inline-block;
margin-bottom: 0;
width: 60px;
text-align: left;
padding-right: 12px;
}
.info-container {
display: flex;
align-items: center;
gap: 40px;
padding: 0 20px 18px;
color: #333;
font-size: 16px;
}
.info-item {
white-space: nowrap;
}
</style>

1021
src/views/UserPermissions/TemplateLimit.vue
File diff suppressed because it is too large
View File

733
src/views/UserPermissions/TokenManage.vue

@ -0,0 +1,733 @@
<template>
<div class="page-container">
<!-- 搜索区域 -->
<div class="search-container" @keyup.enter="searchDM">
<div class="search-form">
<div class="search-group">
<div class="search-group1">
<div class="search-item">
<span class="form-label">账号</span>
<el-input
v-model="searchFormDM.dccode"
placeholder="请输入账号"
clearable
style="height: 36px; width: 140px;"
/>
</div>
<div class="search-item">
<span class="form-label">姓名</span>
<el-input
v-model="searchFormDM.dcname"
placeholder="请输入姓名"
clearable
style="height: 36px; width: 180px;"
/>
</div>
<div class="search-item">
<span class="form-label">归属</span>
<el-input
v-model="searchFormDM.inviter"
placeholder="请输入归属账号"
clearable
style="height: 36px; width: 140px;"
/>
</div>
</div>
<div class="search-group2">
<div class="search-item">
<span class="form-label">客户类型</span>
<el-select
v-model="searchFormDM.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-item">
<span class="form-label">地区</span>
<el-select
v-model="searchFormDM.market"
placeholder="请选择地区"
clearable
filterable
style="height: 36px; width: 160px;"
:loading="isRegionLoading"
>
<el-option
v-for="region in regionList"
:key="region.ID"
:label="region.Name"
:value="region.ID"
/>
</el-select>
</div>
</div>
</div>
<div class="button-group">
<el-button type="primary" @click="searchDM">搜索</el-button>
<el-button type="danger" @click="enableAccessDM">开通权限</el-button>
<el-button type="success" @click="exportExcelDM">导出Excel列表</el-button>
<el-button color="#626aef" @click="exportListDM">查看导出列表</el-button>
<el-button type="primary" @click="resetBnDM">重置</el-button>
</div>
</div>
</div>
<!-- 数据 -->
<el-table
:data="tableDataDM"
style="width: 100%; margin-top: 20px;"
header-cell-class-name="table-header"
@sort-change="handleSortChangeDM"
:default-sort="{ order: null }"
class="table-rounded"
:loading="tableLoadingDM"
>
<el-table-column prop="id" label="序号" align="center" header-align="center" width="80">
<template #default="scope">
{{ (currentPageDM - 1) * pageSizeDM + 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="inviter" label="归属" align="center" header-align="center"/>
<el-table-column prop="module_name" label="模块名称" align="center" header-align="center"/>
<el-table-column prop="remain_num" label="token数量" align="center" header-align="center"/>
<el-table-column prop="remain_free_num" label="免费token" align="center" header-align="center"/>
<el-table-column prop="remain_pay_num" label="付费token" align="center" header-align="center"/>
<el-table-column prop="updated_at" label="操作时间" align="center" header-align="center" sortable="custom"/>
<el-table-column label="操作" align="center" header-align="center">
<template #default="scope">
<el-button type="text" @click="handleEditDM(scope.row)">编辑</el-button>
<el-button type="text" @click="handleLogDM(scope.row.dccode)">操作日志</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="demo-pagination-block">
<el-pagination
@size-change="handleSizeChangeDM"
@current-change="handleCurrentChangeDM"
:current-page="currentPageDM"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSizeDM"
layout="total, sizes, prev, pager, next, jumper"
:total= "datatotalDM"
/>
</div>
<!-- 开通/编辑弹窗 -->
<el-dialog v-model="dialogVisibleDM" :title="addOrUpdataDM === 1 ? '添加权限' : '修改'" width="500px" :before-close="cancelDM">
<!-- 设置用户 -->
<div class="form-item" v-if="addOrUpdataDM === 1">
<label class="form-label">设置用户</label>
<el-input type="textarea" v-model="hlidsInput" rows=10
placeholder="请输入HLid...
示例
90048004
90048005
90048006"
/>
<div class="tip">支持批量输入每次最多1000个手动/Excel粘贴均可</div>
</div>
<!-- 编辑回显 -->
<div class="info-container" v-if="addOrUpdataDM === 0">
<span class="info-item">HLid: {{ hlidsInput }}</span>
<span class="info-item">剩余次数{{ deadtoken }}</span>
<span class="info-item">免费token{{ deadtokenFree }}</span>
<span class="info-item">付费token{{ deadtokenPay }}</span>
</div>
<!-- 设置数量 -->
<div class="form-item" v-if="addOrUpdataDM === 1">
<label class="form-label">设置用户次数</label>
<div class="count-group">
<!-- Deep Mate不可编辑文本框 -->
<el-input v-model="dmText" disabled style="width: 120px; margin-right: 16px;"/>
<!-- token类型下拉框 -->
<el-select v-model="token_type" style="width: 100px; margin-right: 16px;">
<el-option label="免费token" value="free_num" />
<el-option label="付费token" value="pay_num" />
</el-select>
<!-- token数量只能正整数 -->
<el-input v-model.number="token_num" type="number" style="width: 140px;" placeholder="请输入次数" title="请输入次数(只能为正)"/>
</div>
</div>
<div class="form-item" v-if="addOrUpdataDM === 0">
<label class="form-label">修改用户次数</label>
<div class="count-group">
<!-- Deep Mate不可编辑文本框 -->
<el-input v-model="dmText" disabled style="width: 120px; margin-right: 16px;"/>
<!-- token类型下拉框 -->
<el-select v-model="token_type" style="width: 120px; margin-right: 16px;">
<el-option label="免费token" value="free_num" />
<el-option label="付费token" value="pay_num" />
</el-select>
<!-- token数量支持正负整数 -->
<el-input v-model.number="token_num" type="number" style="width: 140px;" placeholder="请输入次数(可正负)" title="请输入次数(可正负)"/>
</div>
</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="cancelDM">取消</el-button>
<el-button type="primary" @click="submitFormDM" style="background-color: #ff0000; border-color: #ff0000;">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { marketListApi, userDMListApi, exportDeepMateApi, exitDMApi } from '../../api/userPermissions'
import router from '../../router';
// token
const token = localStorage.getItem('token')
//
const regionList = ref([]);
const isRegionLoading = ref(false);
//
const fetchRegionList = async () => {
try {
isRegionLoading.value = true;
const data = await marketListApi({
token: token,
app_form: "en"
});
regionList.value = data.list;
} catch (error) {
console.error('获取地区列表失败:', error);
regionList.value = [];
} finally {
isRegionLoading.value = false;
}
};
// DeepMate
const searchFormDM = reactive({
dccode: '',
dcname: '',
is_login:'',
inviter:'',
market: '',
user_role: ''
});
// DeepMate
const sortOrderDM = ref(null);
// DeepMate
const tableDataDM = ref([]);
const tableLoadingDM = ref(false);
const datatotalDM = ref(0)
// DeepMate
const currentPageDM = ref(1);
const pageSizeDM = ref(10);
// DeepMate
const DMTableData = async () => {
try {
tableLoadingDM.value = true;
const requestParams = {
token: token,
dccode: searchFormDM.dccode,
dcname: searchFormDM.dcname,
is_login: searchFormDM.is_login,
inviter: searchFormDM.inviter,
market: searchFormDM.market,
user_role: searchFormDM.user_role,
sort_order: sortOrderDM.value,
page: currentPageDM.value,
page_size: pageSizeDM.value
};
const data = await userDMListApi(requestParams);
tableDataDM.value = data.list
datatotalDM.value = data.total
} catch (error) {
console.error('获取表格数据失败:', error);
tableDataDM.value = [];
datatotalDM.value = 0
} finally {
tableLoadingDM.value = false;
}
};
// DeepMate
const handleSizeChangeDM = (val) => {
pageSizeDM.value = val;
DMTableData();
console.log(`每页 ${val}`);
};
const handleCurrentChangeDM = (val) => {
currentPageDM.value = val;
DMTableData();
console.log(`当前页: ${val}`);
};
// DeepMate
const handleSortChangeDM = (sort) => {
const { order } = sort;
sortOrderDM.value = order; //
DMTableData();
};
// DeepMate
const searchDM = () => {
currentPageDM.value = 1;
DMTableData();
};
// DeepMate
const resetBnDM = () => {
searchFormDM.dccode = '';
searchFormDM.dcname = '';
searchFormDM.is_login = '';
searchFormDM.inviter = '';
searchFormDM.market = '';
searchFormDM.user_role = '';
sortOrderDM.value = null;
currentPageDM.value = 1;
pageSizeDM.value = 10;
DMTableData();
};
// DeepMate
const enableAccessDM = () => {
dialogVisibleDM.value = true;
addOrUpdataDM.value = 1;
};
// DeepMateExcel
const exportExcelDM = async () => {
const requestParams = {
token: token,
dccode: searchFormDM.dccode,
dcname: searchFormDM.dcname,
is_login: searchFormDM.is_login,
inviter: searchFormDM.inviter,
market: searchFormDM.market,
user_role: searchFormDM.user_role,
sort_order: sortOrderDM.value
};
const data = await exportDeepMateApi(requestParams);
if (data != '') {
ElMessage.success('已导出');
}
};
// DeepMate
const exportListDM = () => {
router.push({
path: "/userPermissions/export"
});
};
// DeepMate
const handleEditDM = (row) => {
dialogVisibleDM.value = true;
hlidsInput.value = row.dccode;
deadtoken.value = row.remain_num;
deadtokenFree.value = row.remain_free_num;
deadtokenPay.value = row.remain_pay_num;
};
// DeepMate
const handleLogDM = (dccode) => {
router.push({
path: "/userPermissions/logDeepMate",
query: { dccode: dccode }
});
};
// DeepMate
const dialogVisibleDM = ref(false);
// DeepMate
const hlidsInput = ref('');
const dmText = ref('Deep Mate');
const token_num = ref('');
const token_type = ref('free_num'); // tokenfree_num-token, pay_num-token
// DeepMate
const deadtoken = ref('');
const deadtokenFree = ref('');
const deadtokenPay = ref('');
// DeepMate
const addOrUpdataDM = ref(0);
// HLid
const checkHlids = () => {
//
if (!hlidsInput.value.trim()) {
ElMessage.error('请输入HLid');
return false;
}
//
const hlidList = hlidsInput.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;
};
// token
const checkTokenNum = () => {
//
if (addOrUpdataDM.value === 1) {
if (token_num.value === null || token_num.value === '') {
ElMessage.error('请输入token数量');
return false;
}
if (!Number.isInteger(token_num.value) || token_num.value <= 0) {
ElMessage.error('token数量必须为正整数');
return false;
}
}
//
else if (addOrUpdataDM.value === 0) {
if (token_num.value === null || token_num.value === '') {
ElMessage.error('请输入token数量');
return false;
}
if (!Number.isInteger(token_num.value)) {
ElMessage.error('token数量必须为整数');
return false;
}
if (token_num.value < 0 && Math.abs(token_num.value) > deadtoken.value) {
ElMessage.error('扣除次数大于当前总次数,请重新输入次数');
return false;
}
}
return true;
};
//
const checkRemark = () => {
if (!remark.value.trim()) {
ElMessage.error('请输入备注');
return false;
}
return true;
};
//
const NoshakeDM = ref(false)
// DeepMate
const submitFormDM = async () => {
//
if (NoshakeDM.value) return;
NoshakeDM.value = true;
//
if (!checkHlids() || !checkTokenNum() || !checkRemark()) {
NoshakeDM.value = false;
return;
}
try {
const requestParams = {
token: token,
// HLid
hlids: hlidsInput.value.split('\n')
.map(item => item.trim())
.filter(item => item)
.join('\n'),
// token
...(token_type.value === 'free_num'
? { free_num: token_num.value }
: { pay_num: token_num.value }),
//
remark: remark.value.trim(),
//
...(operator.value.trim() && { operator: operator.value.trim() }),
};
console.log('传给后端的参数:', requestParams);
//
await exitDMApi(requestParams);
ElMessage.success(addOrUpdataDM.value === 1 ? '用户次数设置成功' : '用户次数修改成功');
//
resetFormDM();
dialogVisibleDM.value = false;
addOrUpdataDM.value = 0;
//
DMTableData();
} catch (error) {
ElMessage.error('添加权限失败,请重试');
} finally {
NoshakeDM.value = false;
}
};
// DeepMate
const cancelDM = () => {
resetFormDM();
dialogVisibleDM.value = false;
addOrUpdataDM.value = 0;
};
// DeepMate
const resetFormDM = () => {
hlidsInput.value = '';
token_num.value = '';
token_type.value = 'free_num';
remark.value = '';
operator.value = '';
};
//
const remark = ref('');
const operator = ref('');
// +
onMounted(() => {
fetchRegionList();
DMTableData();
});
</script>
<style scoped>
/* 父容器 */
.page-container {
position: relative;
min-height: 600px;
}
/* 搜索区域 */
.search-container {
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-form {
display: flex;
align-items: center;
width: 100%;
gap: 15px;
flex-wrap: wrap;
row-gap: 8px;
}
/* 搜索组 */
.search-group {
}
.search-group1{
display: flex;
align-items: center;
gap: 15px;
}
.search-group2{
display: flex;
margin-top: 15px;
align-items: center;
gap: 15px;
}
/* 单个搜索项 */
.search-item {
display: flex;
align-items: center;
gap: 6px;
}
/* 搜索标签文字 */
.form-label {
font-weight: 800 !important;
font-size: 15px;
text-align: left;
color: #333;
margin-top: 13px;
font-family: "SimHei", "Heiti SC", "Microsoft YaHei", sans-serif !important;
}
/* 按钮组 */
.button-group {
display: flex;
align-items: center;
gap: 0px !important;
margin-left: auto;
}
/* 按钮样式 */
.button-group .el-button {
padding: 6px 10px !important;
font-size: 14px !important;
height: 36px !important;
}
/* 表格样式 */
.table-rounded {
border-radius: 12px !important;
overflow: hidden !important;
border: 1px solid #e4e7ed !important;
height: 650px;
}
.table-header {
text-align: center !important;
font-weight: 800 !important;
font-size: 15px !important;
color: #333 !important;
background-color: #f8f9fa !important;
}
.el-table__cell {
border-right: none !important;
border-bottom: 1px solid #e4e7ed !important;
}
.el-table__header th.el-table__cell {
border-right: none !important;
border-bottom: 1px solid #e4e7ed !important;
}
.el-table__row:hover .el-table__cell {
background-color: #fafafa !important;
}
/* 分页组件样式 */
.demo-pagination-block {
display: flex;
width: 100%;
height: 44px;
padding: 0 16px;
align-items: center;
gap: 16px;
position: absolute;
margin-top: 10px;
border-radius: 0 0 3px 3px;
border-top: 1px solid #EAEAEA;
background: #FEFBFB;
box-sizing: border-box;
}
/* 添加/修改样式 */
.form-item {
margin-bottom: 24px;
padding-left: 20px;
padding-right: 20px;
text-align: left;
}
.form-label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
.radio-group {
display: flex;
flex-direction: column;
gap: 12px;
align-items: flex-start;
}
.radio-item {
display: flex;
align-items: center;
}
.radio-item span {
margin-right: 8px;
}
.tip {
font-size: 12px;
color: #909399;
margin-top: 4px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 16px;
margin-top: 20px;
}
.inline-form-item {
display: flex;
align-items: flex-start;
gap: 12px;
}
.inline-form-item .form-label {
display: inline-block;
margin-bottom: 0;
width: 60px;
text-align: left;
padding-right: 12px;
}
.info-container {
display: flex;
align-items: center;
gap: 20px;
padding: 0 20px 18px;
color: #333;
font-size: 14px;
flex-wrap: wrap;
}
.info-item {
white-space: nowrap;
}
</style>
Loading…
Cancel
Save