2025-04-16 10:43:54 +08:00
|
|
|
|
<template>
|
2026-01-15 10:38:53 +08:00
|
|
|
|
<div class="admin_page all-user">
|
|
|
|
|
|
<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>
|
|
|
|
|
|
</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') }}
|
2025-04-16 10:43:54 +08:00
|
|
|
|
</div>
|
2026-01-15 10:38:53 +08:00
|
|
|
|
<div
|
|
|
|
|
|
class="admin_search_item"
|
|
|
|
|
|
style="width: auto; padding: 0 2rem"
|
|
|
|
|
|
@click="ExportAccountData"
|
|
|
|
|
|
>
|
|
|
|
|
|
{{ $t('admin.ExportAccountData') }}
|
|
|
|
|
|
</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">
|
2025-12-16 17:32:33 +08:00
|
|
|
|
<div class="admin_state_list plan_list">
|
|
|
|
|
|
<div
|
|
|
|
|
|
v-for="plan in planFilterOptions"
|
|
|
|
|
|
:key="plan.id"
|
|
|
|
|
|
class="plan_item"
|
2026-01-15 10:47:57 +08:00
|
|
|
|
:class="{
|
2025-12-18 13:29:30 +08:00
|
|
|
|
active: subscriptionPlanId === plan.id,
|
|
|
|
|
|
disabled: plan.status === 'PENDING'
|
|
|
|
|
|
}"
|
|
|
|
|
|
@click="plan.status !== 'PENDING' && selectPlanFilter(plan.id)"
|
2025-12-16 17:32:33 +08:00
|
|
|
|
>
|
|
|
|
|
|
<span class="plan_name">{{ plan.name }}</span>
|
2026-01-15 10:47:57 +08:00
|
|
|
|
<MoreOutlined
|
|
|
|
|
|
class="plan_more_icon"
|
|
|
|
|
|
@click.stop="plan.status !== 'PENDING' && openPlanRenameModal(plan)"
|
2025-12-18 13:29:30 +08:00
|
|
|
|
/>
|
2025-12-16 17:32:33 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-01-15 10:38:53 +08:00
|
|
|
|
<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"
|
2025-04-16 10:43:54 +08:00
|
|
|
|
>
|
2026-01-15 10:38:53 +08:00
|
|
|
|
{{ $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>
|
2026-01-15 10:38:53 +08:00
|
|
|
|
<allUserPoerationsVue
|
|
|
|
|
|
ref="allUserPoerationsVue"
|
|
|
|
|
|
@searchHistoryList="searchHistoryList"
|
2025-12-16 17:32:33 +08:00
|
|
|
|
:plan-options="planFilterOptions"
|
2026-01-15 10:38:53 +08:00
|
|
|
|
></allUserPoerationsVue>
|
2025-12-16 17:32:33 +08:00
|
|
|
|
<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>
|
2026-01-15 10:38:53 +08:00
|
|
|
|
</div>
|
2025-04-16 10:43:54 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
|
import {
|
2026-01-15 10:38:53 +08:00
|
|
|
|
defineComponent,
|
|
|
|
|
|
ref,
|
|
|
|
|
|
createVNode,
|
|
|
|
|
|
computed,
|
|
|
|
|
|
reactive,
|
|
|
|
|
|
toRefs,
|
2025-12-16 17:32:33 +08:00
|
|
|
|
unref,
|
|
|
|
|
|
watch
|
2026-01-15 10:38:53 +08:00
|
|
|
|
} from 'vue'
|
|
|
|
|
|
import { formatTime } from '@/tool/util'
|
|
|
|
|
|
import { useStore } from 'vuex'
|
|
|
|
|
|
import { Https } from '@/tool/https'
|
2025-12-16 17:32:33 +08:00
|
|
|
|
import { Modal, message, Input } from 'ant-design-vue'
|
|
|
|
|
|
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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({
|
2025-12-16 17:32:33 +08:00
|
|
|
|
components: { allUserPoerationsVue, MoreOutlined },
|
2026-01-15 10:38:53 +08:00
|
|
|
|
setup() {
|
|
|
|
|
|
const store: any = useStore()
|
2025-12-16 17:32:33 +08:00
|
|
|
|
const currentOrganizationId = computed(
|
|
|
|
|
|
() => store.state.UserHabit.userDetail.organizationId
|
|
|
|
|
|
)
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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
|
|
|
|
|
2026-01-15 10:38:53 +08:00
|
|
|
|
const { t } = useI18n()
|
2025-09-01 14:03:30 +08:00
|
|
|
|
|
2026-01-15 10:38:53 +08:00
|
|
|
|
let filterData: any = reactive({
|
|
|
|
|
|
rangePickerValue: [],
|
|
|
|
|
|
currentPage: 1,
|
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
|
total: 0,
|
|
|
|
|
|
country: '',
|
|
|
|
|
|
email: '',
|
|
|
|
|
|
userType: '',
|
|
|
|
|
|
ids: [],
|
|
|
|
|
|
occupation: '',
|
|
|
|
|
|
systemUser: '',
|
|
|
|
|
|
order: '', //'Ascending 升序 Descending 降序'
|
|
|
|
|
|
orderBy: '',
|
2025-12-16 17:32:33 +08:00
|
|
|
|
userName: '',
|
|
|
|
|
|
subscriptionPlanId: ''
|
2026-01-15 10:38:53 +08:00
|
|
|
|
})
|
2025-04-16 10:43:54 +08:00
|
|
|
|
|
2026-01-15 10:38:53 +08:00
|
|
|
|
let renameData: any = ref({}) //修改名字选中的数据
|
2025-12-16 17:32:33 +08:00
|
|
|
|
const renamePlanModalVisible = ref(false)
|
|
|
|
|
|
const renamePlanForm = reactive({
|
|
|
|
|
|
planId: null as number | null,
|
|
|
|
|
|
planName: ''
|
|
|
|
|
|
})
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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
|
|
|
|
|
2026-01-15 10:38:53 +08:00
|
|
|
|
gettrialList()
|
|
|
|
|
|
}
|
2025-04-16 10:43:54 +08:00
|
|
|
|
|
2026-01-15 10:38:53 +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 = ''),
|
2025-12-16 17:32:33 +08:00
|
|
|
|
(filterData.userName = ''),
|
|
|
|
|
|
(filterData.subscriptionPlanId = '')
|
2026-01-15 10:38:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
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,
|
2025-12-16 17:32:33 +08:00
|
|
|
|
userName: filterData.ids,
|
|
|
|
|
|
subscriptionPlanId: filterData.subscriptionPlanId
|
2026-01-15 10:38:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
//获取列表
|
2025-12-16 17:32:33 +08:00
|
|
|
|
const gettrialList = () => {
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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
|
2025-04-16 10:43:54 +08:00
|
|
|
|
|
2026-01-15 10:38:53 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
}
|
2025-12-16 17:32:33 +08:00
|
|
|
|
// 订阅计划筛选(按钮点击)
|
|
|
|
|
|
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,
|
2026-01-15 10:47:57 +08:00
|
|
|
|
status: ['ACTIVE', 'PENDING']
|
2025-12-16 17:32:33 +08:00
|
|
|
|
}).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()
|
2026-01-15 10:47:57 +08:00
|
|
|
|
const userSubscriptionPlanId =
|
|
|
|
|
|
store.state.UserHabit.userDetail.subscriptionPlanId
|
2025-12-16 17:32:33 +08:00
|
|
|
|
if (userSubscriptionPlanId) {
|
|
|
|
|
|
selectPlanFilter(userSubscriptionPlanId)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
|
)
|
|
|
|
|
|
// 打开重命名弹窗(基于当前点击的计划)
|
|
|
|
|
|
const openPlanRenameModal = plan => {
|
|
|
|
|
|
renamePlanForm.planId = plan.id
|
|
|
|
|
|
renamePlanForm.planName = plan?.name || ''
|
|
|
|
|
|
renamePlanModalVisible.value = true
|
|
|
|
|
|
console.log(renamePlanForm)
|
|
|
|
|
|
}
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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
|
|
|
|
}
|
2026-01-15 10:38:53 +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()
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-12-16 17:32:33 +08:00
|
|
|
|
|
|
|
|
|
|
// 确认重命名
|
|
|
|
|
|
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 = ''
|
|
|
|
|
|
}
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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,
|
2025-12-16 17:32:33 +08:00
|
|
|
|
deleteAagree,
|
|
|
|
|
|
planFilterOptions,
|
|
|
|
|
|
selectPlanFilter,
|
|
|
|
|
|
openPlanRenameModal,
|
|
|
|
|
|
renamePlanModalVisible,
|
|
|
|
|
|
renamePlanForm,
|
|
|
|
|
|
confirmRenamePlan,
|
|
|
|
|
|
cancelRenamePlan,
|
|
|
|
|
|
fetchSubscribePlanList
|
2026-01-15 10:38:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
historyTableHeight: 0,
|
|
|
|
|
|
handleResizeColumn: (w: any, col: any) => {
|
|
|
|
|
|
col.width = w
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
mounted() {
|
2025-12-18 15:17:40 +08:00
|
|
|
|
this.updateTableHeight()
|
|
|
|
|
|
window.addEventListener('resize', this.updateTableHeight)
|
|
|
|
|
|
},
|
|
|
|
|
|
beforeUnmount() {
|
|
|
|
|
|
window.removeEventListener('resize', this.updateTableHeight)
|
2026-01-15 10:38:53 +08:00
|
|
|
|
},
|
2025-12-18 15:17:40 +08:00
|
|
|
|
methods: {
|
|
|
|
|
|
updateTableHeight() {
|
|
|
|
|
|
const historyTable: any = this.$refs.historyTable
|
|
|
|
|
|
if (historyTable) {
|
|
|
|
|
|
// 为底部分页器预留固定空间,使表格部分高度固定且分页器始终可见
|
|
|
|
|
|
this.historyTableHeight = historyTable.clientHeight - 200
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-16 17:32:33 +08:00
|
|
|
|
}
|
2026-01-15 10:38:53 +08:00
|
|
|
|
})
|
2025-04-16 10:43:54 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
2025-12-18 15:17:40 +08:00
|
|
|
|
.admin_page {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
.admin_table_content {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
2025-04-16 10:43:54 +08:00
|
|
|
|
.admin_page .admin_table_search .admin_state {
|
2026-01-15 10:38:53 +08:00
|
|
|
|
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 {
|
2026-01-15 10:38:53 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
width: 30%;
|
|
|
|
|
|
> .admin_search_item {
|
|
|
|
|
|
height: 4rem;
|
|
|
|
|
|
font-size: 1.6rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-16 17:32:33 +08:00
|
|
|
|
.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;
|
|
|
|
|
|
}
|
2025-12-18 13:29:30 +08:00
|
|
|
|
|
|
|
|
|
|
&.disabled {
|
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
background-color: #d9d9d9;
|
|
|
|
|
|
border-color: #d9d9d9;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
background-color: #d9d9d9;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-16 17:32:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.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;
|
2025-12-16 17:32:33 +08:00
|
|
|
|
align-items: center;
|
|
|
|
|
|
> span {
|
|
|
|
|
|
width: 10rem;
|
|
|
|
|
|
margin-right: 1rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-16 10:43:54 +08:00
|
|
|
|
}
|
2026-01-15 10:38:53 +08:00
|
|
|
|
.all-user {
|
|
|
|
|
|
.admin_table_content {
|
|
|
|
|
|
:deep(.ant-table-wrapper) {
|
2026-01-15 10:47:57 +08:00
|
|
|
|
overflow: hidden;
|
2026-01-15 10:38:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-16 10:43:54 +08:00
|
|
|
|
}
|
2026-01-15 10:38:53 +08:00
|
|
|
|
</style>
|