Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite

This commit is contained in:
X1627315083
2025-12-17 15:33:34 +08:00
8 changed files with 1445 additions and 1029 deletions

View File

@@ -86,6 +86,16 @@
style="width: 250px" style="width: 250px"
/> />
</div> </div>
<div class="admin_state_item" v-if="title?.value == 'Edit'">
<span>{{ $t('admin.SubscribePlan') }}: <span>*</span></span>
<a-select
v-model:value="subscriptionPlanId"
style="width: 250px"
:options="planOptions"
:field-names="{ label: 'name', value: 'id' }"
:placeholder="$t('admin.SelectPlan')"
></a-select>
</div>
</div> </div>
<div class="allUserPoeration_btn admin_page"> <div class="allUserPoeration_btn admin_page">
<div class="admin_search_item" @click="cancelDsign">{{ $t('admin.Close') }}</div> <div class="admin_search_item" @click="cancelDsign">{{ $t('admin.Close') }}</div>
@@ -114,9 +124,16 @@ import md5 from "md5";
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
export default defineComponent({ export default defineComponent({
components: {}, components: {},
props: {
planOptions: {
type: Array,
default: () => []
}
},
emits: ["searchHistoryList"], emits: ["searchHistoryList"],
setup(props, { emit }) { setup(props, { emit }) {
const {t} = useI18n() const {t} = useI18n()
const { planOptions } = toRefs(props)
let operations = reactive({ let operations = reactive({
operationsModal: false, operationsModal: false,
operationsEdit: false, operationsEdit: false,
@@ -130,6 +147,8 @@ export default defineComponent({
password: "", password: "",
oldPassword: "", oldPassword: "",
credits: "", credits: "",
subscriptionPlanId: "",
oldSubscriptionPlanId: ""
}); });
let state = ref([ let state = ref([
{ {
@@ -163,12 +182,18 @@ export default defineComponent({
// operationsData.validStartTime='2024-08-05T00:00:06' // operationsData.validStartTime='2024-08-05T00:00:06'
// operationsData.validEndTime='2024-08-05T00:00:06' // operationsData.validEndTime='2024-08-05T00:00:06'
operationsData.credits = data.creditsUsageLimit; operationsData.credits = data.creditsUsageLimit;
operationsData.subscriptionPlanId = data.subscriptionPlanId || "";
operationsData.oldSubscriptionPlanId = data.subscriptionPlanId || "";
// operationsData.accountId = data.accountId // operationsData.accountId = data.accountId
// operationsData.userName = data.userName // operationsData.userName = data.userName
// operationsData.userEmail = data.userEmail // operationsData.userEmail = data.userEmail
// operationsData.validStartTime = formatTime(data.validStartTime) // operationsData.validStartTime = formatTime(data.validStartTime)
// operationsData.validEndTime = formatTime(data.validEndTime) // operationsData.validEndTime = formatTime(data.validEndTime)
} }
if (funStr.value == "Add") {
operationsData.subscriptionPlanId = "";
operationsData.oldSubscriptionPlanId = "";
}
}; };
let focus = (event) => { let focus = (event) => {
if (operationsData.password == operationsData.oldPassword) { if (operationsData.password == operationsData.oldPassword) {
@@ -187,6 +212,7 @@ export default defineComponent({
userEmail: operationsData.userEmail, userEmail: operationsData.userEmail,
userPassword: operationsData.password?md5(operationsData.password + "abc"):'', userPassword: operationsData.password?md5(operationsData.password + "abc"):'',
userName: operationsData.userName, userName: operationsData.userName,
subscriptionPlanId: operationsData.subscriptionPlanId
}; };
}; };
let setEditData = () => { let setEditData = () => {
@@ -199,6 +225,7 @@ export default defineComponent({
operationsData.password == operationsData.oldPassword operationsData.password == operationsData.oldPassword
? null ? null
: md5(operationsData.password + "abc"), : md5(operationsData.password + "abc"),
subscriptionPlanId: operationsData.subscriptionPlanId
}; };
}; };
let cancelDsign = () => { let cancelDsign = () => {
@@ -207,6 +234,8 @@ export default defineComponent({
operationsData.userEmail = ""; operationsData.userEmail = "";
operationsData.password = ""; operationsData.password = "";
operationsData.credits = ""; operationsData.credits = "";
operationsData.subscriptionPlanId = "";
operationsData.oldSubscriptionPlanId = "";
operations.operationsModal = false; operations.operationsModal = false;
}; };
let setOk = () => { let setOk = () => {
@@ -237,11 +266,26 @@ export default defineComponent({
message.info("The email format is incorrect"); message.info("The email format is incorrect");
return; return;
} }
if (!data.userName || !data.userEmail) if (!data.userName || !data.userEmail || !data.subscriptionPlanId)
return message.warning("Please check the input box marked with *"); return message.warning("Please check the input box marked with *");
const needSwitchPlan =
operationsData.subscriptionPlanId &&
operationsData.subscriptionPlanId !==
operationsData.oldSubscriptionPlanId;
Https.axiosPost(Https.httpUrls.addOrUpdateSubAccount, data).then( Https.axiosPost(Https.httpUrls.addOrUpdateSubAccount, data).then(
(rv) => { (rv) => {
if (rv) { if (rv) {
if (needSwitchPlan) {
Https.axiosGet(
Https.httpUrls.switchSubAccountSubscribePlan,
{
params: {
targetSubscriptionPlanId: operationsData.subscriptionPlanId,
subAccId: operationsData.accountId,
},
}
);
}
cancelDsign(); cancelDsign();
emit("searchHistoryList"); emit("searchHistoryList");
} }
@@ -258,6 +302,7 @@ export default defineComponent({
focus, focus,
blur, blur,
setOk, setOk,
planOptions,
}; };
}, },
data() { data() {

View File

@@ -8,42 +8,14 @@
style="width: 230px" style="width: 230px"
class="range_picker" class="range_picker"
v-model:value="rangePickerValue" v-model:value="rangePickerValue"
:placeholder="[ :placeholder="[$t('HistoryPage.StartDate'), $t('HistoryPage.EndDate')]"
$t('HistoryPage.StartDate'),
$t('HistoryPage.EndDate'),
]"
valueFormat="YYYY-MM-DD" valueFormat="YYYY-MM-DD"
> >
<template #suffixIcon> <template #suffixIcon>
<span <span class="icon iconfont range_picker_icon icon-rili"></span>
class="icon iconfont range_picker_icon icon-rili"
></span>
</template> </template>
</a-range-picker> </a-range-picker>
</div> </div>
<!-- <div class="admin_state_item">
<span>Country or Region:</span>
<a-select
v-model:value="country"
:allowClear="true"
show-search
style="width: 230px"
:filter-option="filterOption"
placeholder="Select Item..."
max-tag-count="responsive"
:options="allCountry"
></a-select>
</div> -->
<!-- <div class="admin_state_item">
<span>Email:</span>
<input
v-model="email"
placeholder="Please enter email"
@keydown.enter="gettrialList"
type="text"
style="width: 230px"
/>
</div> -->
<div class="admin_state_item"> <div class="admin_state_item">
<span>{{ $t('admin.UserName') }}:</span> <span>{{ $t('admin.UserName') }}:</span>
<a-select <a-select
@@ -58,19 +30,6 @@
@keydown.enter="gettrialList" @keydown.enter="gettrialList"
></a-select> ></a-select>
</div> </div>
<!-- <div class="admin_state_item">
<span>User Type:</span>
<a-select
v-model:value="systemUser"
size="large"
style="width: 230px"
optionFilterProp="label"
:options="state"
placeholder="Please select"
allowClear
show-search
></a-select>
</div> -->
</div> </div>
<div class="admin_search"> <div class="admin_search">
<div class="admin_search_item" @click="searchHistoryList"> <div class="admin_search_item" @click="searchHistoryList">
@@ -79,41 +38,60 @@
<div class="admin_search_item" @click="addhHistoryList"> <div class="admin_search_item" @click="addhHistoryList">
{{ $t('admin.add') }} {{ $t('admin.add') }}
</div> </div>
<div class="admin_search_item" style="width: auto;padding: 0 2rem;" @click="downloadTemplate"> <div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="downloadTemplate"
>
{{ $t('admin.DownloadTemplate') }} {{ $t('admin.DownloadTemplate') }}
</div> </div>
<div class="admin_search_item" style="width: auto;padding: 0 2rem;" @click="uploadTemplate"> <div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="uploadTemplate"
>
{{ $t('admin.UploadTemplate') }} {{ $t('admin.UploadTemplate') }}
</div> </div>
<div class="admin_search_item" style="width: auto;padding: 0 2rem;" @click="ExportAccountData"> <div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="ExportAccountData"
>
{{ $t('admin.ExportAccountData') }} {{ $t('admin.ExportAccountData') }}
</div> </div>
<div class="admin_search_item" style="width: auto;padding: 0 2rem;" @click="deleteList"> <div
class="admin_search_item"
style="width: auto; padding: 0 2rem"
@click="deleteList"
>
{{ $t('admin.Delete') }} {{ $t('admin.Delete') }}
</div> </div>
</div> </div>
<div class="admin_state_list"> <div class="admin_state_list">
<div <div class="admin_state_list_item" @click="lastGeTrialList('year')">
class="admin_state_list_item"
@click="lastGeTrialList('year')"
>
{{ $t('admin.NearlyAYear') }} {{ $t('admin.NearlyAYear') }}
</div> </div>
<div <div class="admin_state_list_item" @click="lastGeTrialList('month')">
class="admin_state_list_item"
@click="lastGeTrialList('month')"
>
{{ $t('admin.LastMonth') }} {{ $t('admin.LastMonth') }}
</div> </div>
<div <div class="admin_state_list_item" @click="lastGeTrialList('week')">
class="admin_state_list_item"
@click="lastGeTrialList('week')"
>
{{ $t('admin.LastWeek') }} {{ $t('admin.LastWeek') }}
</div> </div>
</div> </div>
</div> </div>
<div class="admin_table_content" ref="historyTable"> <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 <a-table
@resizeColumn="handleResizeColumn" @resizeColumn="handleResizeColumn"
:loading="tableLoading" :loading="tableLoading"
@@ -123,14 +101,14 @@
rowKey="id" rowKey="id"
:scroll="{ y: historyTableHeight }" :scroll="{ y: historyTableHeight }"
@change="changePage" @change="changePage"
:showSorterTooltip='false' :showSorterTooltip="false"
:pagination="{ :pagination="{
showSizeChanger: true, showSizeChanger: true,
current: currentPage, current: currentPage,
pageSize: pageSize, pageSize: pageSize,
total: total, total: total,
showQuickJumper: true, showQuickJumper: true,
bordered: false, bordered: false
}" }"
> >
<template #bodyCell="{ column, text, record, index }"> <template #bodyCell="{ column, text, record, index }">
@@ -138,27 +116,45 @@
<div <div
class="operate_item" class="operate_item"
@click="setAagree(record)" @click="setAagree(record)"
style="margin-right: 2rem;" style="margin-right: 2rem"
> >
{{ $t('admin.Edit') }} {{ $t('admin.Edit') }}
</div> </div>
<div <div class="operate_item" @click="deleteAagree(record)">
class="operate_item"
@click="deleteAagree(record)"
>
{{ $t('admin.Delete') }} {{ $t('admin.Delete') }}
</div> </div>
<!-- <div
class="operate_item"
@click="deleteGroup(record, index)"
>
Delete
</div> -->
</div> </div>
</template> </template>
</a-table> </a-table>
</div> </div>
<allUserPoerationsVue ref="allUserPoerationsVue" @searchHistoryList="searchHistoryList"></allUserPoerationsVue> <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> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
@@ -170,22 +166,27 @@ import {
reactive, reactive,
toRefs, toRefs,
onMounted, onMounted,
} from "vue"; unref,
import { formatTime } from "@/tool/util"; watch
import { useStore } from "vuex"; } from 'vue'
import { Https } from "@/tool/https"; import { formatTime } from '@/tool/util'
import { Modal,message } from 'ant-design-vue'; import { useStore } from 'vuex'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; import { Https } from '@/tool/https'
import allUserPoerationsVue from "./addAllUser.vue"; import { Modal, message, Input } from 'ant-design-vue'
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
import allUserPoerationsVue from './addAllUser.vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
export default defineComponent({ export default defineComponent({
components: {allUserPoerationsVue,}, components: { allUserPoerationsVue, MoreOutlined },
setup() { setup() {
const store: any = useStore() const store: any = useStore()
const selectedRowKeys = ref([]) as any; const currentOrganizationId = computed(
() => store.state.UserHabit.userDetail.organizationId
)
const selectedRowKeys = ref([]) as any
const onSelectChange = (changableRowKeys: string[]) => { const onSelectChange = (changableRowKeys: string[]) => {
selectedRowKeys.value = changableRowKeys; selectedRowKeys.value = changableRowKeys
}; }
let filter: any = reactive({ let filter: any = reactive({
dataList: [], dataList: [],
tableLoading: false, tableLoading: false,
@@ -196,10 +197,11 @@ export default defineComponent({
rowSelection: computed(() => { rowSelection: computed(() => {
return { return {
selectedRowKeys: unref(selectedRowKeys), selectedRowKeys: unref(selectedRowKeys),
onChange: onSelectChange, onChange: onSelectChange
} }
}) })
}); })
const { t } = useI18n() const { t } = useI18n()
let filterData: any = reactive({ let filterData: any = reactive({
@@ -207,159 +209,154 @@ export default defineComponent({
currentPage: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 0, total: 0,
country: "", country: '',
email: "", email: '',
userType: "", userType: '',
ids: [], ids: [],
occupation: "", occupation: '',
systemUser: "", systemUser: '',
order: "", //'Ascending 升序 Descending 降序' order: '', //'Ascending 升序 Descending 降序'
orderBy: '', orderBy: '',
userName: "", userName: '',
}); subscriptionPlanId: ''
})
let renameData: any = ref({}); //修改名字选中的数据 let renameData: any = ref({}) //修改名字选中的数据
const renamePlanModalVisible = ref(false)
const renamePlanForm = reactive({
planId: null as number | null,
planName: ''
})
const columns: any = computed(() => { const columns: any = computed(() => {
return [ return [
{ {
title: t("admin.UserId"), title: t('admin.UserId'),
align: "center", align: 'center',
dataIndex: "id", dataIndex: 'id',
key: "id", key: 'id',
width: 100, width: 100,
fixed: "left", fixed: 'left',
sorter: true, sorter: true
}, },
{ {
title: t("admin.Email"), title: t('admin.Email'),
align: "center", align: 'center',
dataIndex: "userEmail", dataIndex: 'userEmail',
key: "userEmail", key: 'userEmail',
width: 200, width: 200,
ellipsis: true ellipsis: true
}, },
{ {
title: t("admin.UserName"), title: t('admin.UserName'),
align: "center", align: 'center',
dataIndex: "userName", dataIndex: 'userName',
key: "userName", key: 'userName',
width: 150, width: 150,
ellipsis: true ellipsis: true
// customRender: (record: any) => {
// let time = formatTime(
// record.text / 1000,
// "YYYY-MM-DD hh:mm:ss"
// );
// return time;
// },
}, },
{ {
title: t("admin.language"), title: t('admin.language'),
align: "center", align: 'center',
dataIndex: "language", dataIndex: 'language',
key: "language", key: 'language',
width: 100, width: 100,
ellipsis: true, ellipsis: true,
customRender: (record: any) => { customRender: (record: any) => {
return t(`admin.${record.text}`); return t(`admin.${record.text}`)
}, }
}, },
{ {
title: t("admin.CreateDate"), title: t('admin.CreateDate'),
align: "center", align: 'center',
dataIndex: "createDate", dataIndex: 'createDate',
key: "createDate", key: 'createDate',
width: 200, width: 200,
sorter: true, sorter: true
}, },
{ {
title: t("admin.Credits"), title: t('admin.Credits'),
align: "center", align: 'center',
// width: 150, dataIndex: 'credits',
// minWidth: 100, key: 'credits',
// maxWidth: 200,
// resizable: true,
dataIndex: "credits",
key: "credits",
width: 100, width: 100,
sorter: true, sorter: true
}, },
{ {
title: t("admin.CreditsUsage"), title: t('admin.CreditsUsage'),
align: "center", align: 'center',
dataIndex: "creditsUsage", dataIndex: 'creditsUsage',
key: "creditsUsage", key: 'creditsUsage',
width: 150, width: 150,
sorter: true, sorter: true
}, },
{ {
title: t("admin.CreditsUsageLimit"), title: t('admin.CreditsUsageLimit'),
align: "center", align: 'center',
dataIndex: "creditsUsageLimit", dataIndex: 'creditsUsageLimit',
key: "creditsUsageLimit", key: 'creditsUsageLimit',
width: 200, width: 200,
sorter: true, sorter: true
}, },
{ {
title: t("admin.Operations"), title: t('admin.Operations'),
key: "operation", key: 'operation',
width: 120, width: 120,
align: "center", align: 'center',
fixed: "right", fixed: 'right',
// slots:{customRender:'action'} Operations: true
Operations: true, }
}, ]
]; })
});
//改变页码 //改变页码
let changePage = (e: any, filters: any, sorter: any) => { let changePage = (e: any, filters: any, sorter: any) => {
filterData.currentPage = e.current; filterData.currentPage = e.current
filterData.pageSize = e.pageSize; filterData.pageSize = e.pageSize
if (sorter.order) { if (sorter.order) {
if (sorter.columnKey == 'id') { if (sorter.columnKey == 'id') {
filterData.orderBy = 'id' filterData.orderBy = 'id'
}else if(sorter.columnKey == "createDate"){ } else if (sorter.columnKey == 'createDate') {
filterData.orderBy = 'time' filterData.orderBy = 'time'
}else if(sorter.columnKey == "credits"){ } else if (sorter.columnKey == 'credits') {
filterData.orderBy = 'credits' filterData.orderBy = 'credits'
} }
} }
if (sorter.order) { if (sorter.order) {
filterData.order = sorter.order == "descend" ? "Descending" : "Ascending"; filterData.order = sorter.order == 'descend' ? 'Descending' : 'Ascending'
} else { } else {
filterData.order = '' filterData.order = ''
} }
gettrialList(); gettrialList()
}; }
//查询列表 //查询列表
let searchHistoryList = () => { let searchHistoryList = () => {
filterData.currentPage = 1; filterData.currentPage = 1
gettrialList(); gettrialList()
}; }
let clearHistoryList = () => { let clearHistoryList = () => {
filterData.rangePickerValue = [], ;(filterData.rangePickerValue = []),
filterData.currentPage = 1, (filterData.currentPage = 1),
filterData.pageSize = 10, (filterData.pageSize = 10),
filterData.total = 0, (filterData.total = 0),
filterData.country = "", (filterData.country = ''),
filterData.email = "", (filterData.email = ''),
filterData.userType = "", (filterData.userType = ''),
filterData.ids = [], (filterData.ids = []),
filterData.occupation = "", (filterData.occupation = ''),
filterData.order = "", //'Ascending 升序 Descending 降序' (filterData.order = ''), //'Ascending 升序 Descending 降序'
filterData.orderBy = "", //'Ascending 升序 Descending 降序' (filterData.orderBy = ''), //'Ascending 升序 Descending 降序'
filterData.systemUser = "", (filterData.systemUser = ''),
filterData.userName = ""; (filterData.userName = ''),
}; (filterData.subscriptionPlanId = '')
}
let setHistoryListData = () => { let setHistoryListData = () => {
let startDate: any = filterData.rangePickerValue?.[0] let startDate: any = filterData.rangePickerValue?.[0]
? filterData.rangePickerValue[0] + " " + "00:00:00" ? filterData.rangePickerValue[0] + ' ' + '00:00:00'
: ""; : ''
let endDate: any = filterData.rangePickerValue?.[1] let endDate: any = filterData.rangePickerValue?.[1]
? filterData.rangePickerValue[1] + " " + "23:59:59" ? filterData.rangePickerValue[1] + ' ' + '23:59:59'
: ""; : ''
let data = { let data = {
endTime: endDate, endTime: endDate,
startTime: startDate, startTime: startDate,
@@ -375,100 +372,164 @@ export default defineComponent({
orderBy: filterData.orderBy, orderBy: filterData.orderBy,
// userName: filterData.userName, // userName: filterData.userName,
userName: filterData.ids, userName: filterData.ids,
subscriptionPlanId: filterData.subscriptionPlanId
}; }
return data; return data
}; }
//获取列表 //获取列表
let gettrialList = () => { const gettrialList = () => {
filter.tableLoading = true; filter.tableLoading = true
let data = setHistoryListData(); let data = setHistoryListData()
Https.axiosPost(Https.httpUrls.subAccountList, data).then( Https.axiosPost(Https.httpUrls.subAccountList, data).then((rv: any) => {
(rv: any) => {
if (rv) { if (rv) {
console.log(rv) filter.dataList = rv.content
// this.dataList = rv filterData.total = rv.total
filter.dataList = rv.content; filter.tableLoading = false
filterData.total = rv.total;
filter.tableLoading = false;
// this.workspaceItem.position = this.singleTypeList[0].label // this.workspaceItem.position = this.singleTypeList[0].label
} }
})
} }
);
};
let lastGeTrialList = (str: string) => { let lastGeTrialList = (str: string) => {
clearHistoryList(); clearHistoryList()
let currentDate = new Date(); let currentDate = new Date()
let currentTimestamp = Math.floor(currentDate.getTime() / 1000); let currentTimestamp = Math.floor(currentDate.getTime() / 1000)
// 计算30天前的时间戳 // 计算30天前的时间戳
let thirtyDaysAgoTimestamp; let thirtyDaysAgoTimestamp
if (str == "year") { if (str == 'year') {
thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60; thirtyDaysAgoTimestamp = currentTimestamp - 360 * 24 * 60 * 60
} else if (str == "month") { } else if (str == 'month') {
thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60; thirtyDaysAgoTimestamp = currentTimestamp - 30 * 24 * 60 * 60
} else if (str == "week") { } else if (str == 'week') {
thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60; thirtyDaysAgoTimestamp = currentTimestamp - 7 * 24 * 60 * 60
}
filterData.rangePickerValue[0] = formatTime(thirtyDaysAgoTimestamp, 'YYYY-MM-DD')
gettrialList()
} }
filterData.rangePickerValue[0] = formatTime(
thirtyDaysAgoTimestamp,
"YYYY-MM-DD"
);
gettrialList();
};
let filterOption = (input: any, option: any) => { let filterOption = (input: any, option: any) => {
// 使用 option.label 进行搜索 // 使用 option.label 进行搜索
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0; 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: ['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 = () => { let addhHistoryList = () => {
allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '') allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '')
}; }
let allUserPoerationsVue = ref() let allUserPoerationsVue = ref()
let setAagree = (data: any) => { let setAagree = (data: any) => {
allUserPoerationsVue.value.init({ value: 'Edit', label: t('admin.Edit') }, data) allUserPoerationsVue.value.init({ value: 'Edit', label: t('admin.Edit') }, data)
} }
const downloadTemplate = () => { const downloadTemplate = () => {
Https.axiosGet(Https.httpUrls.subAccountImportExcelDownload,{responseType: 'blob',env:{binary:true}}).then((rv:any)=>{ Https.axiosGet(Https.httpUrls.subAccountImportExcelDownload, {
const link = document.createElement('a'); responseType: 'blob',
link.href = rv.url; env: { binary: true }
link.download = 'file.xlsx'; // 设置正确的文件扩展名 }).then((rv: any) => {
document.body.appendChild(link); const link = document.createElement('a')
link.click(); link.href = rv.url
document.body.removeChild(link); link.download = 'file.xlsx' // 设置正确的文件扩展名
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
// 释放 URL 对象 // 释放 URL 对象
URL.revokeObjectURL(link.href); URL.revokeObjectURL(link.href)
}) })
} }
const ExportAccountData = () => { 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)=>{ Https.axiosGet(Https.httpUrls.exportAccountsToExcel, {
const link = document.createElement('a'); headers: { responseType: 'blob' },
link.href = rv.url; env: {
link.download = 'file.xlsx'; // 设置正确的文件扩展名 binary: true,
document.body.appendChild(link); binaryType:
link.click(); 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'
document.body.removeChild(link); }
}).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 对象
URL.revokeObjectURL(link.href); URL.revokeObjectURL(link.href)
}) })
} }
const uploadTemplate = () => { const uploadTemplate = () => {
const fileInput = document.createElement('input'); const fileInput = document.createElement('input')
fileInput.type = 'file'; fileInput.type = 'file'
fileInput.accept = '.xlsx'; // 只接受 .xlsx 文件 fileInput.accept = '.xlsx' // 只接受 .xlsx 文件
fileInput.onchange = (event: any) => { fileInput.onchange = (event: any) => {
const file = event.target.files[0]; // 获取选择的文件 const file = event.target.files[0] // 获取选择的文件
if (file) { if (file) {
let param = new FormData(); let param = new FormData()
param.append('file',file); param.append('file', file)
let config:any = {headers:{'Content-Type':'multipart/form-data','Accept':'*/*' }} let config: any = {
Https.axiosPost(Https.httpUrls.subAccountImport,param,config) headers: { 'Content-Type': 'multipart/form-data', 'Accept': '*/*' }
.then((rv:any)=>{
gettrialList();
})
} }
}; Https.axiosPost(Https.httpUrls.subAccountImport, param, config).then(
fileInput.click(); (rv: any) => {
gettrialList()
}
)
}
}
fileInput.click()
} }
const confirmDelete = () => { const confirmDelete = () => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
@@ -484,7 +545,7 @@ export default defineComponent({
onCancel() { onCancel() {
resolve(false) resolve(false)
} }
}); })
}) })
} }
const deleteList = async () => { const deleteList = async () => {
@@ -494,9 +555,10 @@ export default defineComponent({
if (!boolean) { if (!boolean) {
return return
} }
Https.axiosPost(Https.httpUrls.deleteSubAccount,{deleteIdList:selectedRowKeys.value}) Https.axiosPost(Https.httpUrls.deleteSubAccount, {
.then((rv:any)=>{ deleteIdList: selectedRowKeys.value
gettrialList(); }).then((rv: any) => {
gettrialList()
}) })
} }
const deleteAagree = async (event: any) => { const deleteAagree = async (event: any) => {
@@ -507,18 +569,44 @@ export default defineComponent({
const value = { const value = {
deleteIdList: [event.id] deleteIdList: [event.id]
} }
Https.axiosPost(Https.httpUrls.deleteSubAccount,value) Https.axiosPost(Https.httpUrls.deleteSubAccount, value).then((rv: any) => {
.then((rv:any)=>{ gettrialList()
gettrialList();
}) })
} }
onMounted(() => {
let allCountry: any = sessionStorage.getItem("allCountry"); // 确认重命名
if (allCountry) { const confirmRenamePlan = () => {
filter.allCountry = JSON.parse(allCountry); if (!renamePlanForm.planName || !renamePlanForm.planName.trim()) {
message.warning(t('admin.PlanNameRequired'))
return
} }
gettrialList();
}); 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 { return {
...toRefs(filter), ...toRefs(filter),
...toRefs(filterData), ...toRefs(filterData),
@@ -537,22 +625,29 @@ export default defineComponent({
uploadTemplate, uploadTemplate,
deleteList, deleteList,
deleteAagree, deleteAagree,
}; planFilterOptions,
selectPlanFilter,
openPlanRenameModal,
renamePlanModalVisible,
renamePlanForm,
confirmRenamePlan,
cancelRenamePlan,
fetchSubscribePlanList
}
}, },
data() { data() {
return { return {
historyTableHeight: 0, historyTableHeight: 0,
handleResizeColumn: (w: any, col: any) => { handleResizeColumn: (w: any, col: any) => {
col.width = w; col.width = w
}, }
}; }
}, },
mounted() { mounted() {
let historyTable: any = this.$refs.historyTable; let historyTable: any = this.$refs.historyTable
this.historyTableHeight = historyTable.clientHeight - 200; this.historyTableHeight = historyTable.clientHeight - 200
}, }
methods: {}, })
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.admin_page .admin_table_search .admin_state { .admin_page .admin_table_search .admin_state {
@@ -570,4 +665,64 @@ export default defineComponent({
font-size: 1.6rem; 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 {
display: flex;
align-items: center;
> span {
width: 10rem;
margin-right: 1rem;
}
}
}
</style> </style>

View File

@@ -58,6 +58,16 @@
:options="allUserList" :options="allUserList"
></a-select> ></a-select>
</a-form-item> </a-form-item>
<a-form-item label="Status">
<a-select
v-model:value="searchForm.status"
mode="multiple"
allow-clear
placeholder="Select Status"
style="width: 220px"
:options="statusOption"
/>
</a-form-item>
<a-form-item> <a-form-item>
<a-space> <a-space>
<a-button type="primary" @click="handleSearch">Search</a-button> <a-button type="primary" @click="handleSearch">Search</a-button>
@@ -69,14 +79,18 @@
<a-card class="table-card" :bordered="false"> <a-card class="table-card" :bordered="false">
<div class="table-card__header"> <div class="table-card__header">
<div class="table-card__title">Subscription Plan</div>
<a-button type="primary" @click="openCreate">New Subscription Plan</a-button> <a-button type="primary" @click="openCreate">New Subscription Plan</a-button>
</div> </div>
<div ref="historyTable" class="table-wrapper">
<a-table <a-table
:data-source="tableData" :data-source="tableData"
:columns="columns" :columns="columns"
:loading="tableLoading" :loading="tableLoading"
:bordered="false"
row-key="id" row-key="id"
@change="changePage"
@resizeColumn="handleResizeColumn"
:scroll="{ y: historyTableHeight }"
:pagination="{ :pagination="{
showSizeChanger: true, showSizeChanger: true,
current: searchForm.page, current: searchForm.page,
@@ -94,13 +108,10 @@
> >
{{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }} {{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }}
</template> </template>
<!-- <template v-if="column.key === 'organizationId'">
{{ organizationOptions.find(item => item.id === record[column.key]).name }}
</template> -->
<template v-if="column.key === 'status'"> <template v-if="column.key === 'status'">
<a-tag :color="statusColorMap[record.status]"> <a-tag :color="getStatusColor(record.status)">
{{ statusLabelMap[record.status] }} {{ record.status }}
</a-tag> </a-tag>
</template> </template>
<template v-if="column.key === 'adminAccId'"> <template v-if="column.key === 'adminAccId'">
@@ -122,6 +133,7 @@
</template> </template>
</template> </template>
</a-table> </a-table>
</div>
</a-card> </a-card>
<div class="subscriptionPlanModal" ref="subscriptionPlanModal"></div> <div class="subscriptionPlanModal" ref="subscriptionPlanModal"></div>
@@ -175,7 +187,7 @@
</div> </div>
<div class="subscriptionPlan_center admin_page"> <div class="subscriptionPlan_center admin_page">
<div class="form_content"> <div class="form_content">
<div class="admin_state_item"> <div class="admin_state_item" v-if="!isEditMode">
<span> <span>
Name: Name:
<span>*</span> <span>*</span>
@@ -184,7 +196,6 @@
v-model:value="formState.name" v-model:value="formState.name"
placeholder="Input the name" placeholder="Input the name"
style="width: 250px" style="width: 250px"
:disabled="isEditMode"
/> />
</div> </div>
<div class="admin_state_item"> <div class="admin_state_item">
@@ -200,7 +211,6 @@
@popupScroll="handleOrganizationScroll" @popupScroll="handleOrganizationScroll"
@select="handleOrganizationSelect" @select="handleOrganizationSelect"
@change="handleOrganizationChange" @change="handleOrganizationChange"
:disabled="isEditMode"
> >
<a-select-option value="ADD_ORGANIZATION" class="add-organization-option"> <a-select-option value="ADD_ORGANIZATION" class="add-organization-option">
+ 添加组织 + 添加组织
@@ -287,11 +297,21 @@
placeholder="Input the credit limit" placeholder="Input the credit limit"
/> />
</div> </div>
<div class="admin_state_item" v-if="!isEditMode">
<span>Status:</span>
<a-select
v-model:value="formState.status"
placeholder="Select status"
allow-clear
style="width: 250px"
:options="statusOption"
/>
</div>
</div> </div>
</div> </div>
<div class="subscriptionPlan_btn admin_page"> <div class="subscriptionPlan_btn admin_page">
<div class="admin_search_item" @click="cancelModal">Close</div> <div class="admin_search_item" @click="cancelModal">Close</div>
<div class="admin_search_item" @click="handleSubmit">OK</div> <div class="admin_search_item" @click="handleSubmitDebounced">OK</div>
</div> </div>
</a-modal> </a-modal>
@@ -353,14 +373,15 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, computed, nextTick } from 'vue' import { reactive, ref, onMounted, onBeforeUnmount, computed, nextTick, useTemplateRef } from 'vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { Https } from '@/tool/https' import { Https } from '@/tool/https'
import { formatTime } from '@/tool/util' import { formatTime } from '@/tool/util'
import store from '@/store' import store from '@/store'
import type { FormInstance, Rule } from 'ant-design-vue/es/form' import type { FormInstance, Rule } from 'ant-design-vue/es/form'
import { debounce } from 'lodash-es'
type PlanStatus = 'active' | 'paused' | 'ended' type PlanStatus = 'PENDING' | 'ACTIVE' | 'EXPIRED'
interface SubscriptionPlan { interface SubscriptionPlan {
id: number id: number
name: string name: string
@@ -381,6 +402,7 @@ const searchForm = reactive({
endTime: '', endTime: '',
organizationId: undefined as string | undefined, organizationId: undefined as string | undefined,
adminAccId: undefined as string | undefined, adminAccId: undefined as string | undefined,
status: [] as PlanStatus[] | [],
id: '', id: '',
page: 1, page: 1,
size: 10, size: 10,
@@ -403,7 +425,8 @@ const formState = reactive({
organizationId: undefined as string | undefined, organizationId: undefined as string | undefined,
adminAccId: undefined as string | undefined, adminAccId: undefined as string | undefined,
creditLimit: null as number | null, creditLimit: null as number | null,
accountNum: null as number | null accountNum: null as number | null,
status: undefined as PlanStatus | undefined
}) })
const organizationModalVisible = ref(false) const organizationModalVisible = ref(false)
@@ -413,55 +436,110 @@ const organizationForm = reactive({
}) })
const statusLabelMap: Record<PlanStatus, string> = { const statusLabelMap: Record<PlanStatus, string> = {
active: 'Active', PENDING: 'Pending',
paused: 'Paused', ACTIVE: 'Active',
ended: 'Ended' EXPIRED: 'Expired'
} }
const statusColorMap: Record<PlanStatus, string> = { const statusColorMap: Record<PlanStatus, string> = {
active: 'green', PENDING: 'blue',
paused: 'orange', ACTIVE: 'green',
ended: 'red' EXPIRED: 'red'
} }
const statusOption = ref([
{
label: 'Pending',
value: 'PENDING'
},
{
label: 'Active',
value: 'ACTIVE'
},
{
label: 'Expired',
value: 'EXPIRED'
}
])
const normalizeStatus = (status?: string): PlanStatus | undefined => {
if (!status) return undefined
const upper = status.toUpperCase() as PlanStatus
return upper
}
const getStatusColor = (status?: string) =>
statusColorMap[normalizeStatus(status) as PlanStatus] || 'default'
const columns = [ const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' }, { title: 'Name', dataIndex: 'name', key: 'name', align: 'center',width: 180 },
{ title: 'ID', dataIndex: 'id', key: 'id' }, { title: 'ID', dataIndex: 'id', key: 'id', align: 'center' ,width: 80},
{ title: 'Organization', dataIndex: 'organizationName', key: 'organizationName' }, {
{ title: 'Admin Account', dataIndex: 'adminAccId', key: 'adminAccId' }, title: 'Organization',
{ title: 'Account Num', dataIndex: 'accountNum', key: 'accountNum' }, dataIndex: 'organizationName',
key: 'organizationName',
align: 'center',
width: 180
},
{ title: 'Admin Account', dataIndex: 'adminAccId', key: 'adminAccId', align: 'center' ,width: 180},
{ title: 'Account Num', dataIndex: 'accountNum', key: 'accountNum', align: 'center' ,width: 120},
{ {
title: 'Start Time', title: 'Start Time',
dataIndex: 'currentPeriodStart', dataIndex: 'currentPeriodStart',
key: 'currentPeriodStart' key: 'currentPeriodStart',
align: 'center',
width:200
}, },
{ {
title: 'End Time', title: 'End Time',
dataIndex: 'currentPeriodEnd', dataIndex: 'currentPeriodEnd',
key: 'currentPeriodEnd' key: 'currentPeriodEnd',
align: 'center',
width:200
}, },
{ title: 'Status', dataIndex: 'status', key: 'status' }, { title: 'Status', dataIndex: 'status', key: 'status', align: 'center' ,width: 100},
{ title: 'Credit Limit', dataIndex: 'creditLimit', key: 'creditLimit' }, {
{ title: 'Operations', key: 'actions', width: 160 } title: 'Credit Limit',
dataIndex: 'creditLimit',
key: 'creditLimit',
align: 'center',
width: 120
},
{ title: 'Operations', key: 'actions', width: 160, align: 'center', fixed: 'right' }
] ]
const historyTable = ref()
const historyTableHeight = ref(0)
const handleResizeColumn = (w: any, col: any) => {
col.width = w
}
const calculateTableHeight = () => {
nextTick(() => {
if (historyTable.value) {
historyTableHeight.value = historyTable.value.clientHeight - 200
}
})
}
const handleResize = () => {
calculateTableHeight()
}
onMounted(async () => { onMounted(async () => {
await getOrganizationList() await getOrganizationList()
await handleSearch() await handleSearch()
calculateTableHeight()
window.addEventListener('resize', handleResize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
}) })
const handleFetchTableData = async () => { const handleFetchTableData = async () => {
tableLoading.value = true tableLoading.value = true
return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm) return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm)
.then(res => { .then(res => {
tableData.value = res.records.map(item => { tableData.value = res.records
const organization = organizationOptions.value.find(
el => el.id === item.organizationId
) || { name: '' }
return {
...item,
organizationName: organization.name || ''
}
debugger
})
searchForm.total = res.total searchForm.total = res.total
}) })
.finally(() => { .finally(() => {
@@ -477,6 +555,13 @@ const resetFormState = () => {
formState.adminAccId = undefined formState.adminAccId = undefined
formState.creditLimit = null formState.creditLimit = null
formState.accountNum = null formState.accountNum = null
formState.status = undefined
}
const changePage = (pagination: any) => {
searchForm.page = pagination.current
searchForm.size = pagination.pageSize
handleFetchTableData()
} }
const handleSearch = () => { const handleSearch = () => {
@@ -490,6 +575,7 @@ const handleReset = () => {
searchForm.endTime = '' searchForm.endTime = ''
searchForm.organizationId = undefined searchForm.organizationId = undefined
searchForm.adminAccId = undefined searchForm.adminAccId = undefined
searchForm.status = []
searchForm.id = '' searchForm.id = ''
handleSearch() handleSearch()
} }
@@ -508,12 +594,37 @@ const openEdit = (record: SubscriptionPlan) => {
modalTitle.value = 'Edit Subscription Plan' modalTitle.value = 'Edit Subscription Plan'
isEditMode.value = true isEditMode.value = true
formState.name = record.name formState.name = record.name
formState.currentPeriodStart = record.currentPeriodStart formState.currentPeriodStart = String(record.currentPeriodStart)
formState.currentPeriodEnd = record.currentPeriodEnd formState.currentPeriodEnd = String(record.currentPeriodEnd)
formState.organizationId = record.organizationId formState.organizationId = record.organizationId
formState.adminAccId = record.adminAccId formState.adminAccId = record.adminAccId
formState.creditLimit = record.creditLimit formState.creditLimit = record.creditLimit
formState.accountNum = (record as any).accountNum || null formState.accountNum = (record as any).accountNum || null
formState.status = record.status
formState.id = record.id
// 检查组织ID是否在已加载的组织列表中如果不在则添加临时项
if (record.organizationId) {
const orgExists = organizationOptions.value.some(
(org: any) =>
org.id === record.organizationId ||
String(org.id) === String(record.organizationId)
)
if (!orgExists) {
// 从表格数据中获取组织名称,如果存在则添加临时项
const orgName = (record as any).organizationName
if (orgName) {
organizationOptions.value = [
{
id: record.organizationId,
name: orgName
},
...organizationOptions.value
]
}
}
}
modalVisible.value = true modalVisible.value = true
} }
@@ -590,6 +701,12 @@ const handleSubmit = async () => {
} }
} }
// 防抖包装,避免重复点击
const handleSubmitDebounced = debounce(handleSubmit, 500, {
leading: true,
trailing: false
})
const cancelModal = () => { const cancelModal = () => {
modalVisible.value = false modalVisible.value = false
resetFormState() resetFormState()
@@ -631,12 +748,24 @@ const getOrganizationList = async (isLoadMore = false) => {
} }
organizationLoading.value = true organizationLoading.value = true
try { try {
const rv: any = await Https.axiosPost( const { total, ...requestParams } = organizationParams
Https.httpUrls.queryOrganization, const rv: any = await Https.axiosPost(Https.httpUrls.queryOrganization, requestParams)
organizationParams
)
if (rv) { if (rv) {
organizationOptions.value = [...organizationOptions.value, ...(rv.records || [])] const newRecords = rv.records || []
// 遍历新数据,如果已存在则覆盖,不存在则追加
newRecords.forEach((newOrg: any) => {
const newOrgId = String(newOrg.id)
const existingIndex = organizationOptions.value.findIndex(
(org: any) => String(org.id) === newOrgId
)
if (existingIndex !== -1) {
// 如果已存在,用新数据覆盖旧项
organizationOptions.value[existingIndex] = newOrg
} else {
// 如果不存在,追加到末尾
organizationOptions.value.push(newOrg)
}
})
organizationParams.total = rv.total || 0 organizationParams.total = rv.total || 0
} }
} finally { } finally {
@@ -725,33 +854,64 @@ const filterOption = (input: string, option: any) => {
<style lang="less" scoped> <style lang="less" scoped>
.subscription-plan { .subscription-plan {
padding: 20px 24px 32px 0; padding: 2rem 2.4rem 3.2rem 0;
display: flex;
height: 100%;
flex-direction: column;
.search-card { .search-card {
margin-bottom: 16px; margin-bottom: 1.6rem;
} }
.table-card { .table-card {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
:deep(.ant-card-body) {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 2.4rem;
}
.table-card__header { .table-card__header {
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
align-items: center; margin-bottom: 2.6rem;
margin-bottom: 12px; flex-shrink: 0;
.table-card__title {
font-size: 18px;
font-weight: 500;
} }
.table-wrapper {
flex: 1;
overflow: hidden;
min-height: 0;
} }
.danger-text { .danger-text {
color: #ff4d4f; color: #ff4d4f;
} }
:deep(.ant-table-cell::before) {
display: none;
}
:deep(.ant-table-thead > tr > th) {
border-bottom: none;
}
:deep(.ant-table-tbody > tr > td) {
border: none;
}
:deep(.ant-table-tbody > tr:hover > td) {
background: rgb(202, 202, 202);
}
} }
} }
:deep(.subscriptionPlan_modal) { :deep(.subscriptionPlan_modal) {
.ant-modal-body { .ant-modal-body {
height: calc(65rem * 1.2); // height: calc(65rem * 1.2);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 2.5rem 3rem; padding: 2.5rem 3rem;

View File

@@ -1530,7 +1530,22 @@ export default {
Relight: '打光', Relight: '打光',
ChatRobot: '对话生成', ChatRobot: '对话生成',
Yes: '是', Yes: '是',
No: '否' No: '否',
SubscribePlan: '订阅计划',
SwitchPlanSuccess: '切换订阅计划成功',
SwitchPlanFailed: '切换订阅计划失败',
NoPlanSelected: '请先选择订阅计划',
PlanNameRequired: '请输入计划名称',
PlanNotFound: '计划不存在',
RenamePlanSuccess: '重命名成功',
RenamePlanFailed: '重命名失败',
RenamePlan: '重命名订阅计划',
PlanName: '计划名称',
InputPlanName: '请输入计划名称',
OK: '确定',
Cancel: '取消',
SelectPlan: '选择计划',
AllPlan: '全部'
}, },
Login: { Login: {
Login: '登录', Login: '登录',

View File

@@ -1574,7 +1574,22 @@ export default {
Relight: 'Relight', Relight: 'Relight',
ChatRobot: 'ChatRobot', ChatRobot: 'ChatRobot',
Yes: 'Yes', Yes: 'Yes',
No: 'No' No: 'No',
SubscribePlan:'Subscribe Plan',
SwitchPlanSuccess: 'Switch subscription plan successfully',
SwitchPlanFailed: 'Failed to switch subscription plan',
NoPlanSelected: 'Please select a subscription plan first',
PlanNameRequired: 'Please enter plan name',
PlanNotFound: 'Plan not found',
RenamePlanSuccess: 'Rename successfully',
RenamePlanFailed: 'Failed to rename',
RenamePlan: 'Rename Subscription Plan',
PlanName: 'Plan Name',
InputPlanName: 'Please enter plan name',
OK: 'OK',
Cancel: 'Cancel',
SelectPlan: 'Select Plan',
AllPlan:'All'
}, },
Login: { Login: {
Login: 'Login', Login: 'Login',

View File

@@ -80,12 +80,14 @@ const userHabit : Module<UserHabit,RootState> = {
systemList:[], systemList:[],
expireTime:null, expireTime:null,
language:'', language:'',
organizationId: null,
timeData:{ timeData:{
isExpiration:false, isExpiration:false,
text:'' text:''
}, },
subscriptionType:null, subscriptionType:null,
subscriptionId:null, subscriptionId:null,
subscriptionPlanId:null,
usernameModify:0, usernameModify:0,
occupation:'',//职业 occupation:'',//职业
country:'',//国家 country:'',//国家
@@ -195,12 +197,14 @@ const userHabit : Module<UserHabit,RootState> = {
systemList:[], systemList:[],
expireTime:null, expireTime:null,
language:'', language:'',
organizationId: null,
timeData:{ timeData:{
isExpiration:false, isExpiration:false,
text:'' text:''
}, },
subscriptionType:null, subscriptionType:null,
subscriptionId:null, subscriptionId:null,
subscriptionPlanId:null,
//是否是affiliate用户 //是否是affiliate用户
affiliate:false, affiliate:false,
usernameModify:0, usernameModify:0,
@@ -230,6 +234,7 @@ const userHabit : Module<UserHabit,RootState> = {
state.userDetail.avatar = data.avatar//头像 state.userDetail.avatar = data.avatar//头像
state.userDetail.country = data.country//头像 state.userDetail.country = data.country//头像
state.userDetail.occupation = data.occupation//头像 state.userDetail.occupation = data.occupation//头像
state.userDetail.organizationId = data.organizationId //所属组织
state.userDetail.usernameModify = data.usernameModify//当月剩余修改次数 state.userDetail.usernameModify = data.usernameModify//当月剩余修改次数
state.userDetail.isBeginner = data.isBeginner == 1 ? true : false;//是否完成新手指引 state.userDetail.isBeginner = data.isBeginner == 1 ? true : false;//是否完成新手指引
state.userDetail.title = data.title//当月剩余修改次数 state.userDetail.title = data.title//当月剩余修改次数
@@ -315,6 +320,7 @@ const userHabit : Module<UserHabit,RootState> = {
state.userDetail.status = data.status//当前订阅类型 state.userDetail.status = data.status//当前订阅类型
// state.userDetail.status = data.status || 'active'//当前订阅类型 // state.userDetail.status = data.status || 'active'//当前订阅类型
state.userDetail.subscriptionId = data.subscriptionId//最新订阅id state.userDetail.subscriptionId = data.subscriptionId//最新订阅id
state.userDetail.subscriptionPlanId = data.subscriptionPlanId//最新订阅计划id
}, },
setUpgradePlan(state,data){ setUpgradePlan(state,data){
state.upgradePlan.value = data state.upgradePlan.value = data

View File

@@ -160,11 +160,9 @@ export const Https = {
endpoint: `api/third/party/your-secured-endpoint`, //获取唯一标识是否存在 endpoint: `api/third/party/your-secured-endpoint`, //获取唯一标识是否存在
designWorksRegister: '/api/account/designWorksRegister', //注册 designWorksRegister: '/api/account/designWorksRegister', //注册
designWorksRegisterCode: '/api/account/designWorksRegisterCode', //注册 designWorksRegisterCode: '/api/account/designWorksRegisterCode', //注册
preLogin: '/api/account/preLogin', //预先登入 preLogin: '/api/account/preLogin', //预先登入
schoolLogin: '/api/account/schoolLogin', //学校管理员登录 schoolLogin: '/api/account/schoolLogin', //学校管理员登录
enterpriseLogin: '/api/account/enterpriseLogin', //企业管理员登录 enterpriseLogin: '/api/account/enterpriseLogin', //企业管理员登录
@@ -260,8 +258,6 @@ export const Https = {
poselikeOrDisike: `/api/generate/likeOrDislike`, //postTransform like poselikeOrDisike: `/api/generate/likeOrDislike`, //postTransform like
getAllPose: `/api/generate/getAllPose`, //获取动作 getAllPose: `/api/generate/getAllPose`, //获取动作
//拼贴 //拼贴
genSketchRecon: `/api/generate/genSketchRecon`, genSketchRecon: `/api/generate/genSketchRecon`,
saveReconCanvas: `/api/generate/saveReconCanvas`, saveReconCanvas: `/api/generate/saveReconCanvas`,
@@ -328,9 +324,10 @@ export const Https = {
createSubscribePlan: '/api/subscription_plan/createPlan', // 创建订阅计划 createSubscribePlan: '/api/subscription_plan/createPlan', // 创建订阅计划
deleteSubscribePlan: '/api/subscription_plan/deletePlan', // 删除订阅计划 deleteSubscribePlan: '/api/subscription_plan/deletePlan', // 删除订阅计划
updateSubscribePlan: '/api/subscription_plan/updatePlan', // 修改订阅计划 updateSubscribePlan: '/api/subscription_plan/updatePlan', // 修改订阅计划
searchAllSubscribePlan: '/api/subscription_plan/searchByPage', // 查询所有订阅计划 searchAllSubscribePlan: '/api/subscription_plan/searchByPage', // 分页查询所有订阅计划
switchSubscribePlan:'/api/subscription_plan/switchSubscriptionPlan', // 切换订阅计划 searchSubscribeByOrg: '/api/subscription_plan/searchByOrganizationIdAndStatus', // 不分页查询
switchSubscribePlan: '/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
switchSubAccountSubscribePlan: '/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
//云生成 //云生成
designCloud: `/api/design/designCloud`, //创建云生成 designCloud: `/api/design/designCloud`, //创建云生成
@@ -384,7 +381,6 @@ export const Https = {
getTasksHistory: `/api/tasks/getAllTask`, //获取所有任务列表 getTasksHistory: `/api/tasks/getAllTask`, //获取所有任务列表
prepareForSR: `/api/python/prepareForSR`, //超分 prepareForSR: `/api/python/prepareForSR`, //超分
//作品广场 //作品广场
publish: `/api/portfolio/publish`, //发布作品到作品广场 publish: `/api/portfolio/publish`, //发布作品到作品广场
getPorfolio: `/api/portfolio/page`, //查询作品广场 getPorfolio: `/api/portfolio/page`, //查询作品广场
@@ -444,8 +440,7 @@ export const Https = {
getHistoryNotification: `/api/message/getHistoryNotification`, //获取历史消息 getHistoryNotification: `/api/message/getHistoryNotification`, //获取历史消息
oneClickRead: `/api/message/oneClickRead`, //全部设为已读 oneClickRead: `/api/message/oneClickRead`, //全部设为已读
personalHomepage: `/api/account/personalHomepage`, //获取个人主页信息 personalHomepage: `/api/account/personalHomepage`, //获取个人主页信息
refreshMinioUrl:`/api/third/party/refreshMinioUrl`,//获取可以使用的minio地址 refreshMinioUrl: `/api/third/party/refreshMinioUrl` //获取可以使用的minio地址
}, },
axiosGet(url, config) { axiosGet(url, config) {
@@ -454,12 +449,15 @@ export const Https = {
resolve('') resolve('')
return return
} }
axios.get(url,config).then(response => { axios
.get(url, config)
.then(response => {
resolve(response) resolve(response)
}).catch((error) => { })
.catch(error => {
reject(error) reject(error)
}) })
}); })
}, },
axiosPut(url, data) { axiosPut(url, data) {
@@ -468,12 +466,15 @@ export const Https = {
resolve('') resolve('')
return return
} }
axios.put(url, data).then(response => { axios
.put(url, data)
.then(response => {
resolve(response) resolve(response)
}).catch((error) => { })
.catch(error => {
reject(error) reject(error)
}) })
}); })
}, },
axiosPost(url, data, config) { axiosPost(url, data, config) {
@@ -482,12 +483,15 @@ export const Https = {
resolve('') resolve('')
return return
} }
axios.post(url, data,config).then(response => { axios
.post(url, data, config)
.then(response => {
resolve(response) resolve(response)
}).catch((error) => { })
.catch(error => {
reject(error) reject(error)
}) })
}); })
}, },
axiosDelete(url, newData) { axiosDelete(url, newData) {
@@ -496,16 +500,14 @@ export const Https = {
resolve('') resolve('')
return return
} }
axios.delete(url,{data:newData}).then(response => { axios
.delete(url, { data: newData })
.then(response => {
resolve(response) resolve(response)
}).catch((error) => { })
.catch(error => {
reject(error) reject(error)
}) })
}); })
}, }
} }

View File

@@ -17,14 +17,14 @@
mode="inline" mode="inline"
@click="handleClick" @click="handleClick"
> >
<div v-for="(menu) in rootSubmenuKeys" :key="menu.key" > <div v-for="(menu) in rootSubmenuKeys" :key="`menu-${menu.key}`" >
<a-menu-item :key="menu.key" :name="menu.name" :route="menu.route" v-if="!menu.children"> <a-menu-item :key="`item-${menu.key}`" :name="menu.name" :route="menu.route" v-if="!menu.children">
<template #icon> <template #icon>
<span :class="['icon','iconfont', 'menu_icon', menu.icon]"></span> <span :class="['icon','iconfont', 'menu_icon', menu.icon]"></span>
</template> </template>
<span class="menu_title" :title="menu.name">{{menu.name}}</span> <span class="menu_title" :title="menu.name">{{menu.name}}</span>
</a-menu-item> </a-menu-item>
<a-sub-menu :key="menu.key" v-else> <a-sub-menu :key="`sub-${menu.key}`" v-else>
<template #icon> <template #icon>
<span :class="['icon','iconfont', 'menu_icon', menu.icon]"></span> <span :class="['icon','iconfont', 'menu_icon', menu.icon]"></span>
</template> </template>
@@ -67,7 +67,7 @@
<script lang="ts"> <script lang="ts">
import { LoadingOutlined } from "@ant-design/icons-vue"; import { LoadingOutlined } from "@ant-design/icons-vue";
import { message, Upload } from "ant-design-vue"; import { message, Upload } from "ant-design-vue";
import { defineComponent, onMounted, h, ref, nextTick, computed,reactive, toRefs, onBeforeMount } from "vue"; import { defineComponent, onMounted, h, ref, nextTick, computed,reactive, toRefs, onBeforeMount, watch } from "vue";
import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons-vue'; import { MailOutlined, AppstoreOutlined, SettingOutlined } from '@ant-design/icons-vue';
import { Https } from "@/tool/https"; import { Https } from "@/tool/https";
import { useStore } from "vuex"; import { useStore } from "vuex";
@@ -102,11 +102,38 @@ export default defineComponent({
// 5,7 // 5,7
rootSubmenuKeys: [], rootSubmenuKeys: [],
openKeys: [], openKeys: [],
selectedKeys: ['sub1'], selectedKeys: [],
nowPageName:'All User',//当前页面名称 nowPageName:'All User',//当前页面名称
}); });
let routers:any = ref([]) let routers:any = ref([])
const syncMenuStatus = (path:string)=>{
if(!state.rootSubmenuKeys.length)return
let matched = false
state.rootSubmenuKeys.some((item:any)=>{
if(item.children){
const target = item.children.find((child:any)=>child.route === path)
if(target){
state.selectedKeys = [target.key]
state.openKeys = [`sub-${item.key}`]
state.nowPageName = target.name
matched = true
return true
}
}else if(item.route === path){
state.selectedKeys = [`item-${item.key}`]
state.openKeys = []
state.nowPageName = item.name
matched = true
return true
}
return false
})
if(!matched){
state.selectedKeys = []
}
}
const onOpenChange = (openKeys: string[]) => { const onOpenChange = (openKeys: string[]) => {
const latestOpenKey:any = openKeys.find(key => state.openKeys.indexOf(key) === -1); const latestOpenKey:any = openKeys.find(key => state.openKeys.indexOf(key) === -1);
@@ -150,24 +177,12 @@ export default defineComponent({
state.rootSubmenuKeys = adminRouter.all(t); state.rootSubmenuKeys = adminRouter.all(t);
} }
const route = router.currentRoute.value const route = router.currentRoute.value
if(state.rootSubmenuKeys.some((item:any) => item.route === route.path) || route.path == "/administrator"){ const isMenuRoute = state.rootSubmenuKeys.some((item:any) => item.route === route.path || item.children?.some((child:any)=>child.route === route.path))
// 如果是管理员首页或未匹配菜单,才重定向到首个菜单;否则保持当前路由,避免刷新回到 allUser
if (route.path === "/administrator" || !isMenuRoute) {
router.push(state.rootSubmenuKeys[0].route) router.push(state.rootSubmenuKeys[0].route)
}else{
router.push('/administrator')
} }
// state.rootSubmenuKeys.forEach((item:any) => { syncMenuStatus(router.currentRoute.value.path)
// if(item.children){
// item.children.forEach((item:any) => {
// if(item.route == router.currentRoute.value.path){
// state.selectedKeys[0] = item.key
// }
// });
// }else{
// if(item.route == router.currentRoute.value.path){
// state.selectedKeys[0] = item.key
// }
// }
// });
//储存所有用户id和name //储存所有用户id和name
Https.axiosGet(Https.httpUrls.getAllUserId,).then((rv: any) => { Https.axiosGet(Https.httpUrls.getAllUserId,).then((rv: any) => {
if (rv) { if (rv) {
@@ -192,8 +207,11 @@ export default defineComponent({
// router.push(state.rootSubmenuKeys[0].route) // router.push(state.rootSubmenuKeys[0].route)
}) })
watch(()=>router.currentRoute.value.path,(path)=>{
syncMenuStatus(path)
},{immediate:true})
onBeforeMount(()=>{ onBeforeMount(()=>{
state.selectedKeys = ['sub1'] state.selectedKeys = []
}) })
return { return {
...toRefs(state), ...toRefs(state),