10 changed files with 3138 additions and 23 deletions
-
21src/api/userPermissions.js
-
48src/router/index.js
-
3src/views/UserPermissions/LogDeepExplore.vue
-
4src/views/UserPermissions/LogDeepMate.vue
-
2src/views/UserPermissions/LogMarket.vue
-
18src/views/UserPermissions/Market.vue
-
827src/views/UserPermissions/MarketTerm.vue
-
1022src/views/UserPermissions/TemplateLimit.vue
-
734src/views/UserPermissions/TokenManage.vue
-
482src/views/UserPermissions/UserList.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> |
||||
1022
src/views/UserPermissions/TemplateLimit.vue
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,734 @@ |
|||||
|
<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="country" 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; |
||||
|
}; |
||||
|
|
||||
|
// DeepMate导出Excel列表按钮 |
||||
|
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'); // token类型:free_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> |
||||
@ -0,0 +1,482 @@ |
|||||
|
<template> |
||||
|
<div class="page-container"> |
||||
|
<!-- 搜索区域 --> |
||||
|
<div class="search-container"> |
||||
|
<div class="search-form"> |
||||
|
<div class="search-row"> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">账号</span> |
||||
|
<el-input |
||||
|
v-model="searchForm.dccode" |
||||
|
placeholder="请输入ID" |
||||
|
clearable |
||||
|
style="width: 140px;" |
||||
|
/> |
||||
|
</div> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">姓名</span> |
||||
|
<el-input |
||||
|
v-model="searchForm.name" |
||||
|
placeholder="请输入姓名" |
||||
|
clearable |
||||
|
style="width: 140px;" |
||||
|
/> |
||||
|
</div> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">来源</span> |
||||
|
<el-select |
||||
|
v-model="searchForm.origin_id" |
||||
|
placeholder="请选择来源" |
||||
|
clearable |
||||
|
filterable |
||||
|
style="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.country" |
||||
|
placeholder="请选择地区" |
||||
|
clearable |
||||
|
filterable |
||||
|
style="width: 140px;" |
||||
|
:loading="isRegionLoading" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="region in regionList" |
||||
|
:key="region.ID" |
||||
|
:label="region.Name" |
||||
|
:value="region.Name" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</div> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">登录</span> |
||||
|
<el-select |
||||
|
v-model="searchForm.is_login" |
||||
|
placeholder="请选择是否登录" |
||||
|
clearable |
||||
|
style="width: 140px;" |
||||
|
> |
||||
|
<el-option label="已登录" :value="1" /> |
||||
|
<el-option label="未登录" :value="0" /> |
||||
|
</el-select> |
||||
|
</div> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">注册方式</span> |
||||
|
<el-input |
||||
|
v-model="searchForm.register_type" |
||||
|
placeholder="请输入手机号/邮箱" |
||||
|
clearable |
||||
|
style="width: 180px;" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="search-row"> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">注册时间</span> |
||||
|
<el-date-picker |
||||
|
v-model="searchForm.regTimeRange" |
||||
|
type="datetimerange" |
||||
|
range-separator="至" |
||||
|
start-placeholder="开始时间" |
||||
|
end-placeholder="结束时间" |
||||
|
value-format="YYYY-MM-DD HH:mm:ss" |
||||
|
style="width: 320px;" |
||||
|
/> |
||||
|
</div> |
||||
|
<div class="search-item"> |
||||
|
<span class="form-label">登录时间</span> |
||||
|
<el-date-picker |
||||
|
v-model="searchForm.loginTimeRange" |
||||
|
type="datetimerange" |
||||
|
range-separator="至" |
||||
|
start-placeholder="开始时间" |
||||
|
end-placeholder="结束时间" |
||||
|
value-format="YYYY-MM-DD HH:mm:ss" |
||||
|
style="width: 320px;" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="button-group"> |
||||
|
<el-button type="primary" @click="handleSearch">搜索</el-button> |
||||
|
<el-button type="success" @click="handleExport">导出Excel列表</el-button> |
||||
|
<el-button color="#626aef" @click="handleViewExport">查看导出列表</el-button> |
||||
|
<el-button @click="handleReset">重置</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 数据表格 --> |
||||
|
<el-table |
||||
|
:data="tableData" |
||||
|
style="width: 100%; margin-top: 20px;" |
||||
|
header-cell-class-name="table-header" |
||||
|
class="table-rounded" |
||||
|
:loading="tableLoading" |
||||
|
:header-cell-style="{background:'#f5f7fa', color:'#606266', fontWeight:'600'}" |
||||
|
> |
||||
|
<el-table-column prop="id" label="序号" align="center" header-align="center" width="60"> |
||||
|
<template #default="scope"> |
||||
|
{{ (currentPage - 1) * pageSize + scope.$index + 1 }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="dccode" label="ID" align="center" header-align="center" width="100"/> |
||||
|
<el-table-column prop="name" label="姓名" align="center" header-align="center" width="120"> |
||||
|
<template #default="scope"> |
||||
|
<span>{{ scope.row.name || '-' }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="country" label="地区" align="center" header-align="center" width="120"/> |
||||
|
<el-table-column prop="origin" label="来源" align="center" header-align="center" width="160"> |
||||
|
<template #default="scope"> |
||||
|
<span class="ellipsis-text" :title="scope.row.origin">{{ scope.row.origin }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="phone" label="手机号" align="center" header-align="center" width="120"> |
||||
|
<template #default="scope"> |
||||
|
<span>{{ scope.row.phone || '-' }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="emails" label="邮箱" align="center" header-align="center" width="200"> |
||||
|
<template #default="scope"> |
||||
|
<span class="ellipsis-text" :title="scope.row.emails">{{ scope.row.emails || '-' }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="inviter" label="邀请人" align="center" header-align="center" width="100"> |
||||
|
<template #default="scope"> |
||||
|
<span>{{ scope.row.inviter || '-' }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="is_login" label="是否登录" align="center" header-align="center" width="90"> |
||||
|
<template #default="scope"> |
||||
|
<el-tag v-if="scope.row.is_login == 1" type="success" size="small" effect="light" class="login-tag">登录过</el-tag> |
||||
|
<el-tag v-else type="info" size="small" effect="light">未登录</el-tag> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="reg_time" label="注册时间" align="center" header-align="center" width="160"> |
||||
|
<template #default="scope"> |
||||
|
{{ scope.row.reg_time }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="last_login_time" label="登录时间" align="center" header-align="center" width="160"> |
||||
|
<template #default="scope"> |
||||
|
{{ scope.row.last_login_time }} |
||||
|
</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="total" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, reactive, onMounted } from 'vue'; |
||||
|
import { ElMessage } from 'element-plus'; |
||||
|
import router from '../../router'; |
||||
|
import { |
||||
|
marketListApi, |
||||
|
getOriginListApi, |
||||
|
userListApi, |
||||
|
exportUserListApi |
||||
|
} from '../../api/userPermissions'; |
||||
|
|
||||
|
// token |
||||
|
const token = localStorage.getItem('token') |
||||
|
|
||||
|
// 搜索表单 |
||||
|
const searchForm = reactive({ |
||||
|
dccode: '', |
||||
|
name: '', |
||||
|
origin_id: '', |
||||
|
country: '', |
||||
|
is_login: '', |
||||
|
register_type: '', |
||||
|
regTimeRange: [], |
||||
|
loginTimeRange: [] |
||||
|
}); |
||||
|
|
||||
|
// 地区列表 |
||||
|
const regionList = ref([]); |
||||
|
const isRegionLoading = ref(false); |
||||
|
|
||||
|
// 来源列表 |
||||
|
const originList = ref([]); |
||||
|
const isOriginLoading = ref(false); |
||||
|
|
||||
|
// 表格数据 |
||||
|
const tableData = ref([]); |
||||
|
const tableLoading = ref(false); |
||||
|
const total = ref(0); |
||||
|
|
||||
|
// 分页参数 |
||||
|
const currentPage = ref(1); |
||||
|
const pageSize = ref(10); |
||||
|
|
||||
|
// 获取地区列表 |
||||
|
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 fetchOriginList = async () => { |
||||
|
try { |
||||
|
isOriginLoading.value = true; |
||||
|
const data = await getOriginListApi({ token: token }); |
||||
|
originList.value = data.list || []; |
||||
|
} catch (error) { |
||||
|
console.error('获取来源列表失败:', error); |
||||
|
originList.value = []; |
||||
|
} finally { |
||||
|
isOriginLoading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 判断输入是手机号还是邮箱 |
||||
|
const isEmail = (value) => { |
||||
|
const trimmedValue = value?.trim() || ''; |
||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; |
||||
|
return emailRegex.test(trimmedValue); |
||||
|
}; |
||||
|
|
||||
|
const isPhone = (value) => { |
||||
|
const trimmedValue = value?.trim() || ''; |
||||
|
const phoneRegex = /^\d{11}$/; |
||||
|
return phoneRegex.test(trimmedValue); |
||||
|
}; |
||||
|
|
||||
|
// 获取表格数据 |
||||
|
const fetchTableData = async () => { |
||||
|
try { |
||||
|
tableLoading.value = true; |
||||
|
|
||||
|
// 根据输入判断是手机号还是邮箱 |
||||
|
const registerType = searchForm.register_type?.trim() || ''; |
||||
|
const isEmailValue = isEmail(registerType); |
||||
|
const isPhoneValue = isPhone(registerType); |
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
page: currentPage.value, |
||||
|
page_size: pageSize.value, |
||||
|
dccode: searchForm.dccode, |
||||
|
name: searchForm.name, |
||||
|
origin_id: searchForm.origin_id, |
||||
|
country: searchForm.country, |
||||
|
is_login: searchForm.is_login, |
||||
|
phone: isPhoneValue ? registerType : '', |
||||
|
is_phone: isPhoneValue ? 1 : 0, |
||||
|
email: isEmailValue ? registerType : '', |
||||
|
reg_time_start: searchForm.regTimeRange && searchForm.regTimeRange[0] ? searchForm.regTimeRange[0] : '', |
||||
|
reg_time_end: searchForm.regTimeRange && searchForm.regTimeRange[1] ? searchForm.regTimeRange[1] : '', |
||||
|
list_login_time_start: searchForm.loginTimeRange && searchForm.loginTimeRange[0] ? searchForm.loginTimeRange[0] : '', |
||||
|
list_login_time_end: searchForm.loginTimeRange && searchForm.loginTimeRange[1] ? searchForm.loginTimeRange[1] : '', |
||||
|
reg_time_asc: '', |
||||
|
list_login_time_asc: '' |
||||
|
}; |
||||
|
|
||||
|
const data = await userListApi(requestParams); |
||||
|
tableData.value = data.list || []; |
||||
|
total.value = data.total || 0; |
||||
|
} catch (error) { |
||||
|
console.error('获取表格数据失败:', error); |
||||
|
tableData.value = []; |
||||
|
total.value = 0; |
||||
|
} finally { |
||||
|
tableLoading.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 搜索 |
||||
|
const handleSearch = () => { |
||||
|
currentPage.value = 1; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
|
||||
|
// 导出Excel |
||||
|
const handleExport = async () => { |
||||
|
try { |
||||
|
// 根据输入判断是手机号还是邮箱 |
||||
|
const registerType = searchForm.register_type?.trim() || ''; |
||||
|
const isEmailValue = isEmail(registerType); |
||||
|
const isPhoneValue = isPhone(registerType); |
||||
|
|
||||
|
const requestParams = { |
||||
|
token: token, |
||||
|
dccode: searchForm.dccode, |
||||
|
name: searchForm.name, |
||||
|
origin_id: searchForm.origin_id, |
||||
|
country: searchForm.country, |
||||
|
is_login: searchForm.is_login, |
||||
|
phone: isPhoneValue ? registerType : '', |
||||
|
is_phone: isPhoneValue ? 1 : 0, |
||||
|
email: isEmailValue ? registerType : '', |
||||
|
reg_time_start: searchForm.regTimeRange && searchForm.regTimeRange[0] ? searchForm.regTimeRange[0] : '', |
||||
|
reg_time_end: searchForm.regTimeRange && searchForm.regTimeRange[1] ? searchForm.regTimeRange[1] : '', |
||||
|
list_login_time_start: searchForm.loginTimeRange && searchForm.loginTimeRange[0] ? searchForm.loginTimeRange[0] : '', |
||||
|
list_login_time_end: searchForm.loginTimeRange && searchForm.loginTimeRange[1] ? searchForm.loginTimeRange[1] : '' |
||||
|
}; |
||||
|
|
||||
|
await exportUserListApi(requestParams); |
||||
|
ElMessage.success('导出任务已创建,请查看导出列表'); |
||||
|
} catch (error) { |
||||
|
console.error('导出失败:', error); |
||||
|
ElMessage.error('导出失败,请重试'); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// 查看导出列表 |
||||
|
const handleViewExport = () => { |
||||
|
router.push({ |
||||
|
path: "/userPermissions/export" |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// 重置 |
||||
|
const handleReset = () => { |
||||
|
searchForm.dccode = ''; |
||||
|
searchForm.name = ''; |
||||
|
searchForm.origin_id = ''; |
||||
|
searchForm.country = ''; |
||||
|
searchForm.is_login = ''; |
||||
|
searchForm.register_type = ''; |
||||
|
searchForm.regTimeRange = []; |
||||
|
searchForm.loginTimeRange = []; |
||||
|
currentPage.value = 1; |
||||
|
pageSize.value = 10; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
|
||||
|
// 分页方法 |
||||
|
const handleSizeChange = (val) => { |
||||
|
pageSize.value = val; |
||||
|
currentPage.value = 1; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
|
||||
|
const handleCurrentChange = (val) => { |
||||
|
currentPage.value = val; |
||||
|
fetchTableData(); |
||||
|
}; |
||||
|
|
||||
|
// 组件挂载时 |
||||
|
onMounted(() => { |
||||
|
fetchRegionList(); |
||||
|
fetchOriginList(); |
||||
|
fetchTableData(); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 页面容器 */ |
||||
|
.page-container { |
||||
|
padding: 20px; |
||||
|
background: #fff; |
||||
|
min-height: calc(100vh - 40px); |
||||
|
} |
||||
|
|
||||
|
/* 搜索区域 */ |
||||
|
.search-container { |
||||
|
background: #fefaf9; |
||||
|
border-radius: 8px; |
||||
|
padding: 20px; |
||||
|
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
.search-form { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 15px; |
||||
|
} |
||||
|
|
||||
|
.search-row { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 15px; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.search-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8px; |
||||
|
} |
||||
|
|
||||
|
.form-label { |
||||
|
font-size: 14px; |
||||
|
color: #333; |
||||
|
white-space: nowrap; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.button-group { |
||||
|
display: flex; |
||||
|
gap: 10px; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
|
||||
|
/* 表格样式 */ |
||||
|
.table-rounded { |
||||
|
border-radius: 8px; |
||||
|
overflow: hidden; |
||||
|
border: 1px solid #e4e7ed; |
||||
|
} |
||||
|
|
||||
|
.table-header { |
||||
|
background-color: #f5f7fa !important; |
||||
|
color: #606266; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
.ellipsis-text { |
||||
|
display: inline-block; |
||||
|
max-width: 100%; |
||||
|
overflow: hidden; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
.login-tag { |
||||
|
background-color: #f0f9eb; |
||||
|
border-color: #e1f3d8; |
||||
|
color: #67c23a; |
||||
|
} |
||||
|
|
||||
|
/* 分页 */ |
||||
|
.demo-pagination-block { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
margin-top: 20px; |
||||
|
padding: 10px 0; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue