feat: 教育管理员操作订阅计划& 刷新页面保持当前页面

This commit is contained in:
2025-12-16 17:32:33 +08:00
parent b1bea281ec
commit 41a42b1133
8 changed files with 1208 additions and 941 deletions

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,16 @@
:options="allUserList"
></a-select>
</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-space>
<a-button type="primary" @click="handleSearch">Search</a-button>
@@ -94,13 +104,10 @@
>
{{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }}
</template>
<!-- <template v-if="column.key === 'organizationId'">
{{ organizationOptions.find(item => item.id === record[column.key]).name }}
</template> -->
<template v-if="column.key === 'status'">
<a-tag :color="statusColorMap[record.status]">
{{ statusLabelMap[record.status] }}
<a-tag :color="getStatusColor(record.status)">
{{ record.status }}
</a-tag>
</template>
<template v-if="column.key === 'adminAccId'">
@@ -200,7 +207,6 @@
@popupScroll="handleOrganizationScroll"
@select="handleOrganizationSelect"
@change="handleOrganizationChange"
:disabled="isEditMode"
>
<a-select-option value="ADD_ORGANIZATION" class="add-organization-option">
+ 添加组织
@@ -291,7 +297,7 @@
</div>
<div class="subscriptionPlan_btn admin_page">
<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>
</a-modal>
@@ -359,8 +365,9 @@ import { Https } from '@/tool/https'
import { formatTime } from '@/tool/util'
import store from '@/store'
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 {
id: number
name: string
@@ -381,6 +388,7 @@ const searchForm = reactive({
endTime: '',
organizationId: undefined as string | undefined,
adminAccId: undefined as string | undefined,
status: [] as PlanStatus[] | [],
id: '',
page: 1,
size: 10,
@@ -413,16 +421,39 @@ const organizationForm = reactive({
})
const statusLabelMap: Record<PlanStatus, string> = {
active: 'Active',
paused: 'Paused',
ended: 'Ended'
PENDING: 'Pending',
ACTIVE: 'Active',
EXPIRED: 'Expired'
}
const statusColorMap: Record<PlanStatus, string> = {
active: 'green',
paused: 'orange',
ended: 'red'
PENDING: 'blue',
ACTIVE: 'green',
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 = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'ID', dataIndex: 'id', key: 'id' },
@@ -452,16 +483,7 @@ const handleFetchTableData = async () => {
tableLoading.value = true
return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm)
.then(res => {
tableData.value = res.records.map(item => {
const organization = organizationOptions.value.find(
el => el.id === item.organizationId
) || { name: '' }
return {
...item,
organizationName: organization.name || ''
}
debugger
})
tableData.value = res.records
searchForm.total = res.total
})
.finally(() => {
@@ -490,6 +512,7 @@ const handleReset = () => {
searchForm.endTime = ''
searchForm.organizationId = undefined
searchForm.adminAccId = undefined
searchForm.status = []
searchForm.id = ''
handleSearch()
}
@@ -508,8 +531,8 @@ const openEdit = (record: SubscriptionPlan) => {
modalTitle.value = 'Edit Subscription Plan'
isEditMode.value = true
formState.name = record.name
formState.currentPeriodStart = record.currentPeriodStart
formState.currentPeriodEnd = record.currentPeriodEnd
formState.currentPeriodStart = String(record.currentPeriodStart)
formState.currentPeriodEnd = String(record.currentPeriodEnd)
formState.organizationId = record.organizationId
formState.adminAccId = record.adminAccId
formState.creditLimit = record.creditLimit
@@ -590,6 +613,12 @@ const handleSubmit = async () => {
}
}
// 防抖包装,避免重复点击
const handleSubmitDebounced = debounce(handleSubmit, 500, {
leading: true,
trailing: false
})
const cancelModal = () => {
modalVisible.value = false
resetFormState()