Files
aida_front/src/component/Administrator/SE/allUser/index.vue

729 lines
21 KiB
Vue
Raw Normal View History

2025-04-16 10:43:54 +08:00
<template>
<div class="admin_page">
<div class="admin_table_search">
<div class="admin_state">
<div class="admin_state_item">
<span>{{ $t('admin.CreateTime') }}:</span>
<a-range-picker
style="width: 230px"
class="range_picker"
v-model:value="rangePickerValue"
:placeholder="[$t('HistoryPage.StartDate'), $t('HistoryPage.EndDate')]"
valueFormat="YYYY-MM-DD"
>
<template #suffixIcon>
<span class="icon iconfont range_picker_icon icon-rili"></span>
</template>
</a-range-picker>
2025-04-16 10:43:54 +08:00
</div>
<div class="admin_state_item">
<span>{{ $t('admin.UserName') }}:</span>
<a-select
v-model:value="ids"
mode="multiple"
style="width: 230px"
:field-names="{ label: 'label', value: 'label' }"
:filter-option="filterOption"
:placeholder="$t('admin.selectUserName')"
max-tag-count="responsive"
:options="allUserList"
@keydown.enter="gettrialList"
></a-select>
</div>
</div>
<div class="admin_search">
<div class="admin_search_item" @click="searchHistoryList">
{{ $t('admin.search') }}
</div>
<div class="admin_search_item" @click="addhHistoryList">
{{ $t('admin.add') }}
</div>
<div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="downloadTemplate"
>
{{ $t('admin.DownloadTemplate') }}
</div>
<div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="uploadTemplate"
>
{{ $t('admin.UploadTemplate') }}
</div>
<div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="ExportAccountData"
>
{{ $t('admin.ExportAccountData') }}
2025-04-16 10:43:54 +08:00
</div>
<div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="deleteList"
>
{{ $t('admin.Delete') }}
</div>
</div>
<div class="admin_state_list">
<div class="admin_state_list_item" @click="lastGeTrialList('year')">
{{ $t('admin.NearlyAYear') }}
</div>
<div class="admin_state_list_item" @click="lastGeTrialList('month')">
{{ $t('admin.LastMonth') }}
</div>
<div class="admin_state_list_item" @click="lastGeTrialList('week')">
{{ $t('admin.LastWeek') }}
</div>
</div>
</div>
<div class="admin_table_content" ref="historyTable">
<div class="admin_state_list plan_list">
<div
v-for="plan in planFilterOptions"
:key="plan.id"
class="plan_item"
:class="{ active: subscriptionPlanId === plan.id }"
@click="selectPlanFilter(plan.id)"
>
<span class="plan_name">{{ plan.name }}</span>
<MoreOutlined class="plan_more_icon" @click.stop="openPlanRenameModal(plan)" />
</div>
</div>
<a-table
@resizeColumn="handleResizeColumn"
:loading="tableLoading"
:columns="columns"
:data-source="dataList"
:row-selection="rowSelection"
rowKey="id"
:scroll="{ y: historyTableHeight }"
@change="changePage"
:showSorterTooltip="false"
:pagination="{
showSizeChanger: true,
current: currentPage,
pageSize: pageSize,
total: total,
showQuickJumper: true,
bordered: false
}"
>
<template #bodyCell="{ column, text, record, index }">
<div class="operate_list" v-if="column?.Operations">
<div
class="operate_item"
@click="setAagree(record)"
style="margin-right: 2rem"
>
{{ $t('admin.Edit') }}
</div>
<div class="operate_item" @click="deleteAagree(record)">
{{ $t('admin.Delete') }}
</div>
</div>
</template>
</a-table>
2025-04-16 10:43:54 +08:00
</div>
<allUserPoerationsVue
ref="allUserPoerationsVue"
@searchHistoryList="searchHistoryList"
:plan-options="planFilterOptions"
></allUserPoerationsVue>
<div class="renamePlanModal" ref="renamePlanModal"></div>
<!-- 重命名订阅计划弹窗 -->
<a-modal
v-model:visible="renamePlanModalVisible"
:title="$t('admin.RenamePlan')"
@ok="confirmRenamePlan"
@cancel="cancelRenamePlan"
:ok-text="$t('admin.OK')"
:cancel-text="$t('admin.Cancel')"
:get-container="() => $refs.renamePlanModal"
>
<div class="rename-plan-form">
<div class="admin_state_item">
<span>{{ $t('admin.PlanName') }}:</span>
<a-input
v-model:value="renamePlanForm.planName"
:placeholder="$t('admin.InputPlanName')"
style="width: 250px"
@pressEnter="confirmRenamePlan"
/>
</div>
</div>
</a-modal>
</div>
2025-04-16 10:43:54 +08:00
</template>
<script lang="ts">
import {
defineComponent,
ref,
createVNode,
computed,
reactive,
toRefs,
onMounted,
unref,
watch
} from 'vue'
import { formatTime } from '@/tool/util'
import { useStore } from 'vuex'
import { Https } from '@/tool/https'
import { Modal, message, Input } from 'ant-design-vue'
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
import allUserPoerationsVue from './addAllUser.vue'
2025-09-01 14:03:30 +08:00
import { useI18n } from 'vue-i18n'
2025-04-16 10:43:54 +08:00
export default defineComponent({
components: { allUserPoerationsVue, MoreOutlined },
setup() {
const store: any = useStore()
const currentOrganizationId = computed(
() => store.state.UserHabit.userDetail.organizationId
)
const selectedRowKeys = ref([]) as any
const onSelectChange = (changableRowKeys: string[]) => {
selectedRowKeys.value = changableRowKeys
}
let filter: any = reactive({
dataList: [],
tableLoading: false,
allUserList: computed(() => {
return store.state.adminPage.allUserList
}),
allCountry: [],
rowSelection: computed(() => {
return {
selectedRowKeys: unref(selectedRowKeys),
onChange: onSelectChange
}
})
})
2025-09-01 14:03:30 +08:00
const { t } = useI18n()
2025-04-16 10:43:54 +08:00
let filterData: any = reactive({
rangePickerValue: [],
currentPage: 1,
pageSize: 10,
total: 0,
country: '',
email: '',
userType: '',
ids: [],
occupation: '',
systemUser: '',
order: '', //'Ascending 升序 Descending 降序'
orderBy: '',
userName: '',
subscriptionPlanId: ''
})
2025-04-16 10:43:54 +08:00
let renameData: any = ref({}) //修改名字选中的数据
const renamePlanModalVisible = ref(false)
const renamePlanForm = reactive({
planId: null as number | null,
planName: ''
})
const columns: any = computed(() => {
return [
{
title: t('admin.UserId'),
align: 'center',
dataIndex: 'id',
key: 'id',
width: 100,
fixed: 'left',
sorter: true
},
{
title: t('admin.Email'),
align: 'center',
dataIndex: 'userEmail',
key: 'userEmail',
width: 200,
ellipsis: true
},
{
title: t('admin.UserName'),
align: 'center',
dataIndex: 'userName',
key: 'userName',
width: 150,
ellipsis: true
},
{
title: t('admin.language'),
align: 'center',
dataIndex: 'language',
key: 'language',
width: 100,
ellipsis: true,
customRender: (record: any) => {
return t(`admin.${record.text}`)
}
},
{
title: t('admin.CreateDate'),
align: 'center',
dataIndex: 'createDate',
key: 'createDate',
width: 200,
sorter: true
},
{
title: t('admin.Credits'),
align: 'center',
dataIndex: 'credits',
key: 'credits',
width: 100,
sorter: true
},
{
title: t('admin.CreditsUsage'),
align: 'center',
dataIndex: 'creditsUsage',
key: 'creditsUsage',
width: 150,
sorter: true
},
{
title: t('admin.CreditsUsageLimit'),
align: 'center',
dataIndex: 'creditsUsageLimit',
key: 'creditsUsageLimit',
width: 200,
sorter: true
},
{
title: t('admin.Operations'),
key: 'operation',
width: 120,
align: 'center',
fixed: 'right',
Operations: true
}
]
})
//改变页码
let changePage = (e: any, filters: any, sorter: any) => {
filterData.currentPage = e.current
filterData.pageSize = e.pageSize
if (sorter.order) {
if (sorter.columnKey == 'id') {
filterData.orderBy = 'id'
} else if (sorter.columnKey == 'createDate') {
filterData.orderBy = 'time'
} else if (sorter.columnKey == 'credits') {
filterData.orderBy = 'credits'
}
}
if (sorter.order) {
filterData.order = sorter.order == 'descend' ? 'Descending' : 'Ascending'
} else {
filterData.order = ''
}
2025-04-16 10:43:54 +08:00
gettrialList()
}
2025-04-16 10:43:54 +08:00
//查询列表
let searchHistoryList = () => {
filterData.currentPage = 1
gettrialList()
}
let clearHistoryList = () => {
;(filterData.rangePickerValue = []),
(filterData.currentPage = 1),
(filterData.pageSize = 10),
(filterData.total = 0),
(filterData.country = ''),
(filterData.email = ''),
(filterData.userType = ''),
(filterData.ids = []),
(filterData.occupation = ''),
(filterData.order = ''), //'Ascending 升序 Descending 降序'
(filterData.orderBy = ''), //'Ascending 升序 Descending 降序'
(filterData.systemUser = ''),
(filterData.userName = ''),
(filterData.subscriptionPlanId = '')
}
let setHistoryListData = () => {
let startDate: any = filterData.rangePickerValue?.[0]
? filterData.rangePickerValue[0] + ' ' + '00:00:00'
: ''
let endDate: any = filterData.rangePickerValue?.[1]
? filterData.rangePickerValue[1] + ' ' + '23:59:59'
: ''
let data = {
endTime: endDate,
startTime: startDate,
size: filterData.pageSize,
page: filterData.currentPage,
systemUser: filterData.systemUser,
country: filterData.country,
// email: filterData.email.trim(),
userType: filterData.userType,
ids: [],
occupation: filterData.occupation,
order: filterData.order,
orderBy: filterData.orderBy,
// userName: filterData.userName,
userName: filterData.ids,
subscriptionPlanId: filterData.subscriptionPlanId
}
return data
}
//获取列表
const gettrialList = () => {
filter.tableLoading = true
let data = setHistoryListData()
Https.axiosPost(Https.httpUrls.subAccountList, data).then((rv: any) => {
if (rv) {
filter.dataList = rv.content
filterData.total = rv.total
filter.tableLoading = false
// this.workspaceItem.position = this.singleTypeList[0].label
}
})
}
let lastGeTrialList = (str: string) => {
clearHistoryList()
let currentDate = new Date()
let currentTimestamp = Math.floor(currentDate.getTime() / 1000)
// 计算30天前的时间戳
let thirtyDaysAgoTimestamp
if (str == 'year') {
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60
} else if (str == 'month') {
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60
} else if (str == 'week') {
thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60
}
filterData.rangePickerValue[0] = formatTime(thirtyDaysAgoTimestamp, 'YYYY-MM-DD')
gettrialList()
}
let filterOption = (input: any, option: any) => {
// 使用 option.label 进行搜索
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
// 订阅计划筛选(按钮点击)
const selectPlanFilter = async (planId: string) => {
filterData.subscriptionPlanId = planId
// 切换管理员订阅计划
Https.axiosGet(Https.httpUrls.switchSubscribePlan, {
params: {
targetSubscriptionPlanId: planId,
adminAccId: store.state.UserHabit.userDetail.id
}
}).then((res: any) => {
console.log(res)
})
searchHistoryList()
}
const planFilterOptions = ref([])
const fetchSubscribePlanList = () => {
const orgId = currentOrganizationId.value
if (!orgId) return
Https.axiosPost(Https.httpUrls.searchSubscribeByOrg, {
organizationId: orgId,
status: ['PENDING', 'ACTIVE']
}).then(res => {
// 将与当前用户 subscriptionPlanId 相同的订阅计划放到第一个
const userSubscriptionPlanId = store.state.UserHabit.userDetail.subscriptionPlanId
if (userSubscriptionPlanId && Array.isArray(res)) {
const sortedList = [...res].sort((a: any, b: any) => {
const isAUserPlan = a.id == userSubscriptionPlanId
const isBUserPlan = b.id == userSubscriptionPlanId
if (isAUserPlan && !isBUserPlan) return -1
if (!isAUserPlan && isBUserPlan) return 1
return 0
})
planFilterOptions.value = sortedList
} else {
planFilterOptions.value = res
}
})
}
// 监听组织ID获取到值后再拉取订阅计划
watch(
() => currentOrganizationId.value,
orgId => {
if (orgId) {
fetchSubscribePlanList()
const userSubscriptionPlanId = store.state.UserHabit.userDetail.subscriptionPlanId
if (userSubscriptionPlanId) {
selectPlanFilter(userSubscriptionPlanId)
}
}
},
{ immediate: true }
)
// 打开重命名弹窗(基于当前点击的计划)
const openPlanRenameModal = plan => {
renamePlanForm.planId = plan.id
renamePlanForm.planName = plan?.name || ''
renamePlanModalVisible.value = true
console.log(renamePlanForm)
}
let addhHistoryList = () => {
allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '')
}
let allUserPoerationsVue = ref()
let setAagree = (data: any) => {
allUserPoerationsVue.value.init({ value: 'Edit', label: t('admin.Edit') }, data)
}
const downloadTemplate = () => {
Https.axiosGet(Https.httpUrls.subAccountImportExcelDownload, {
responseType: 'blob',
env: { binary: true }
}).then((rv: any) => {
const link = document.createElement('a')
link.href = rv.url
link.download = 'file.xlsx' // 设置正确的文件扩展名
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
// 释放 URL 对象
URL.revokeObjectURL(link.href)
})
}
const ExportAccountData = () => {
Https.axiosGet(Https.httpUrls.exportAccountsToExcel, {
headers: { responseType: 'blob' },
env: {
binary: true,
binaryType:
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'
}
}).then((rv: any) => {
const link = document.createElement('a')
link.href = rv.url
link.download = 'file.xlsx' // 设置正确的文件扩展名
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
// 释放 URL 对象
URL.revokeObjectURL(link.href)
})
}
const uploadTemplate = () => {
const fileInput = document.createElement('input')
fileInput.type = 'file'
fileInput.accept = '.xlsx' // 只接受 .xlsx 文件
fileInput.onchange = (event: any) => {
const file = event.target.files[0] // 获取选择的文件
if (file) {
let param = new FormData()
param.append('file', file)
let config: any = {
headers: { 'Content-Type': 'multipart/form-data', 'Accept': '*/*' }
}
Https.axiosPost(Https.httpUrls.subAccountImport, param, config).then(
(rv: any) => {
gettrialList()
2025-04-16 10:43:54 +08:00
}
)
}
}
fileInput.click()
}
const confirmDelete = () => {
return new Promise<void>((resolve, reject) => {
Modal.confirm({
title: t('admin.jsDelete'),
icon: createVNode(ExclamationCircleOutlined),
okText: 'Yes',
cancelText: 'No',
centered: true,
onOk() {
resolve(true)
},
onCancel() {
resolve(false)
}
})
})
}
const deleteList = async () => {
console.log(selectedRowKeys.value)
if (selectedRowKeys.value.length == 0) return
let boolean: any = await confirmDelete()
if (!boolean) {
return
}
Https.axiosPost(Https.httpUrls.deleteSubAccount, {
deleteIdList: selectedRowKeys.value
}).then((rv: any) => {
gettrialList()
})
}
const deleteAagree = async (event: any) => {
let boolean: any = await confirmDelete()
if (!boolean) {
return
}
const value = {
deleteIdList: [event.id]
}
Https.axiosPost(Https.httpUrls.deleteSubAccount, value).then((rv: any) => {
gettrialList()
})
}
// 确认重命名
const confirmRenamePlan = () => {
if (!renamePlanForm.planName || !renamePlanForm.planName.trim()) {
message.warning(t('admin.PlanNameRequired'))
return
}
Https.axiosPost(Https.httpUrls.updateSubscribePlan, {
id: renamePlanForm.planId,
name: renamePlanForm.planName.trim()
})
.then((rv: any) => {
message.success(t('admin.RenamePlanSuccess'))
renamePlanModalVisible.value = false
fetchSubscribePlanList()
})
.catch((error: any) => {
message.error(error.message || t('admin.RenamePlanFailed'))
})
}
// 取消重命名
const cancelRenamePlan = () => {
renamePlanModalVisible.value = false
renamePlanForm.planId = null
renamePlanForm.planName = ''
}
onMounted(() => {
let allCountry: any = sessionStorage.getItem('allCountry')
if (allCountry) {
filter.allCountry = JSON.parse(allCountry)
}
gettrialList()
})
return {
...toRefs(filter),
...toRefs(filterData),
columns,
renameData,
changePage,
searchHistoryList,
addhHistoryList,
lastGeTrialList,
gettrialList,
filterOption,
allUserPoerationsVue,
setAagree,
downloadTemplate,
ExportAccountData,
uploadTemplate,
deleteList,
deleteAagree,
planFilterOptions,
selectPlanFilter,
openPlanRenameModal,
renamePlanModalVisible,
renamePlanForm,
confirmRenamePlan,
cancelRenamePlan,
fetchSubscribePlanList
}
},
data() {
return {
historyTableHeight: 0,
handleResizeColumn: (w: any, col: any) => {
col.width = w
}
}
},
mounted() {
let historyTable: any = this.$refs.historyTable
this.historyTableHeight = historyTable.clientHeight - 200
}
})
2025-04-16 10:43:54 +08:00
</script>
<style lang="less" scoped>
.admin_page .admin_table_search .admin_state {
display: flex;
width: 70%;
flex-wrap: wrap;
align-content: flex-start;
2025-04-16 10:43:54 +08:00
}
.admin_page .admin_table_search .admin_search {
display: flex;
flex-wrap: wrap;
width: 30%;
> .admin_search_item {
height: 4rem;
font-size: 1.6rem;
}
}
.plan_list {
margin-top: 1rem;
display: flex;
// flex-wrap: wrap;
padding-left: 2.8rem;
column-gap: 0.6rem;
margin-bottom: 2rem;
.plan_item {
height: 4rem;
width: auto;
min-width: 10rem;
display: flex;
align-items: center;
justify-content: center;
// font-size: 1.8rem;
font-weight: 600;
border-radius: 1.3rem;
color: #fff;
cursor: pointer;
border: 1.8px solid #000;
background-color: #000;
padding: 0 1rem 0 2rem;
&:hover {
color: #000;
background-color: #fff;
}
&.active {
background: #ffffff;
color: #000000;
}
}
.plan_item {
column-gap: 0.6rem;
}
.plan_more_icon {
font-size: 1.6rem;
cursor: pointer;
}
}
.subscription-plan-cell {
display: flex;
align-items: center;
justify-content: center;
}
.rename-plan-form {
padding: 2rem 0;
.admin_state_item {
2025-04-16 10:43:54 +08:00
display: flex;
align-items: center;
> span {
width: 10rem;
margin-right: 1rem;
}
}
2025-04-16 10:43:54 +08:00
}
</style>