feat: 编辑时不可修改订阅计划状态&布局修改
This commit is contained in:
@@ -79,56 +79,61 @@
|
|||||||
|
|
||||||
<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>
|
||||||
<a-table
|
<div ref="historyTable" class="table-wrapper">
|
||||||
:data-source="tableData"
|
<a-table
|
||||||
:columns="columns"
|
:data-source="tableData"
|
||||||
:loading="tableLoading"
|
:columns="columns"
|
||||||
row-key="id"
|
:loading="tableLoading"
|
||||||
:pagination="{
|
:bordered="false"
|
||||||
showSizeChanger: true,
|
row-key="id"
|
||||||
current: searchForm.page,
|
@change="changePage"
|
||||||
pageSize: searchForm.size,
|
@resizeColumn="handleResizeColumn"
|
||||||
total: searchForm.total,
|
:scroll="{ y: historyTableHeight }"
|
||||||
showQuickJumper: true,
|
:pagination="{
|
||||||
bordered: false
|
showSizeChanger: true,
|
||||||
}"
|
current: searchForm.page,
|
||||||
>
|
pageSize: searchForm.size,
|
||||||
<template #bodyCell="{ column, record }">
|
total: searchForm.total,
|
||||||
<template
|
showQuickJumper: true,
|
||||||
v-if="
|
bordered: false
|
||||||
column.key === 'currentPeriodStart' || column.key === 'currentPeriodEnd'
|
}"
|
||||||
"
|
>
|
||||||
>
|
<template #bodyCell="{ column, record }">
|
||||||
{{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }}
|
<template
|
||||||
</template>
|
v-if="
|
||||||
|
column.key === 'currentPeriodStart' || column.key === 'currentPeriodEnd'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }}
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-if="column.key === 'status'">
|
<template v-if="column.key === 'status'">
|
||||||
<a-tag :color="getStatusColor(record.status)">
|
<a-tag :color="getStatusColor(record.status)">
|
||||||
{{ record.status }}
|
{{ record.status }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'adminAccId'">
|
<template v-if="column.key === 'adminAccId'">
|
||||||
{{ allUserList.find(item => item.value === record.adminAccId)?.label }}
|
{{ allUserList.find(item => item.value === record.adminAccId)?.label }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="column.key === 'actions'">
|
<template v-else-if="column.key === 'actions'">
|
||||||
<a-space>
|
<a-space>
|
||||||
<a @click="openEdit(record)">Edit</a>
|
<a @click="openEdit(record)">Edit</a>
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
title="Confirm to delete this subscription plan?"
|
title="Confirm to delete this subscription plan?"
|
||||||
ok-text="Confirm"
|
ok-text="Confirm"
|
||||||
cancel-text="Cancel"
|
cancel-text="Cancel"
|
||||||
@confirm="removePlan(record.id)"
|
@confirm="removePlan(record.id)"
|
||||||
>
|
>
|
||||||
<a class="danger-text">Delete</a>
|
<a class="danger-text">Delete</a>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
</a-space>
|
</a-space>
|
||||||
|
</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>
|
||||||
@@ -182,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>
|
||||||
@@ -191,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">
|
||||||
@@ -293,7 +297,7 @@
|
|||||||
placeholder="Input the credit limit"
|
placeholder="Input the credit limit"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="admin_state_item">
|
<div class="admin_state_item" v-if="!isEditMode">
|
||||||
<span>Status:</span>
|
<span>Status:</span>
|
||||||
<a-select
|
<a-select
|
||||||
v-model:value="formState.status"
|
v-model:value="formState.status"
|
||||||
@@ -369,7 +373,7 @@
|
|||||||
</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'
|
||||||
@@ -466,28 +470,69 @@ const getStatusColor = (status?: string) =>
|
|||||||
statusColorMap[normalizeStatus(status) as PlanStatus] || 'default'
|
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 () => {
|
||||||
@@ -513,6 +558,12 @@ const resetFormState = () => {
|
|||||||
formState.status = undefined
|
formState.status = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changePage = (pagination: any) => {
|
||||||
|
searchForm.page = pagination.current
|
||||||
|
searchForm.size = pagination.pageSize
|
||||||
|
handleFetchTableData()
|
||||||
|
}
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
searchForm.page = 1
|
searchForm.page = 1
|
||||||
handleFetchTableData()
|
handleFetchTableData()
|
||||||
@@ -555,7 +606,9 @@ const openEdit = (record: SubscriptionPlan) => {
|
|||||||
// 检查组织ID是否在已加载的组织列表中,如果不在,则添加临时项
|
// 检查组织ID是否在已加载的组织列表中,如果不在,则添加临时项
|
||||||
if (record.organizationId) {
|
if (record.organizationId) {
|
||||||
const orgExists = organizationOptions.value.some(
|
const orgExists = organizationOptions.value.some(
|
||||||
(org: any) => org.id === record.organizationId || String(org.id) === String(record.organizationId)
|
(org: any) =>
|
||||||
|
org.id === record.organizationId ||
|
||||||
|
String(org.id) === String(record.organizationId)
|
||||||
)
|
)
|
||||||
if (!orgExists) {
|
if (!orgExists) {
|
||||||
// 从表格数据中获取组织名称,如果存在则添加临时项
|
// 从表格数据中获取组织名称,如果存在则添加临时项
|
||||||
@@ -695,25 +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) {
|
||||||
const newRecords = rv.records || []
|
const newRecords = rv.records || []
|
||||||
// 去重:如果新数据中包含已存在的组织ID,则移除旧项(包括临时项),保留新项
|
// 遍历新数据,如果已存在则覆盖,不存在则追加
|
||||||
const existingIds = new Set(
|
newRecords.forEach((newOrg: any) => {
|
||||||
organizationOptions.value.map((org: any) => String(org.id))
|
const newOrgId = String(newOrg.id)
|
||||||
)
|
const existingIndex = organizationOptions.value.findIndex(
|
||||||
const newIds = new Set(newRecords.map((org: any) => String(org.id)))
|
(org: any) => String(org.id) === newOrgId
|
||||||
|
)
|
||||||
// 移除会被新数据覆盖的旧项(包括临时项)
|
if (existingIndex !== -1) {
|
||||||
organizationOptions.value = organizationOptions.value.filter(
|
// 如果已存在,用新数据覆盖旧项
|
||||||
(org: any) => !newIds.has(String(org.id))
|
organizationOptions.value[existingIndex] = newOrg
|
||||||
)
|
} else {
|
||||||
|
// 如果不存在,追加到末尾
|
||||||
// 追加新数据
|
organizationOptions.value.push(newOrg)
|
||||||
organizationOptions.value = [...organizationOptions.value, ...newRecords]
|
}
|
||||||
|
})
|
||||||
organizationParams.total = rv.total || 0
|
organizationParams.total = rv.total || 0
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -802,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 {
|
.table-wrapper {
|
||||||
font-size: 18px;
|
flex: 1;
|
||||||
font-weight: 500;
|
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;
|
||||||
|
|||||||
Reference in New Issue
Block a user