style: 去除底边距

This commit is contained in:
2026-04-28 15:05:02 +08:00
parent f30a749f65
commit 4b8554f41e

View File

@@ -437,7 +437,7 @@
</template>
<script setup lang="ts">
import {
import {
reactive,
ref,
onMounted,
@@ -446,18 +446,18 @@ import {
computed,
nextTick,
useTemplateRef
} from "vue"
import SelectUser from "@/component/common/SelectUser.vue"
import { message } from "ant-design-vue"
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"
import dayjs, { Dayjs } from "dayjs"
} from "vue"
import SelectUser from "@/component/common/SelectUser.vue"
import { message } from "ant-design-vue"
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"
import dayjs, { Dayjs } from "dayjs"
type PlanStatus = "PENDING" | "ACTIVE" | "EXPIRED"
interface SubscriptionPlan {
type PlanStatus = "PENDING" | "ACTIVE" | "EXPIRED"
interface SubscriptionPlan {
id: number
userId?: string | number
name: string
@@ -471,9 +471,9 @@ interface SubscriptionPlan {
accountNum?: number
startStamp: number
endStamp: number
}
}
interface UserInfoRecord {
interface UserInfoRecord {
id: number
userEmail?: string
userName?: string
@@ -486,12 +486,12 @@ interface UserInfoRecord {
browserIdentifiers?: string
credits?: number
systemUser?: number | string
}
}
const countryList = ref([])
const userRef = ref(null)
const countryList = ref([])
const userRef = ref(null)
const searchForm = reactive({
const searchForm = reactive({
name: "",
startTime: "",
endTime: "",
@@ -503,27 +503,27 @@ const searchForm = reactive({
page: 1,
size: 10,
total: 0
})
})
const toSeconds = (dateStr: string) => Math.floor(new Date(dateStr).getTime() / 1000)
const toSeconds = (dateStr: string) => Math.floor(new Date(dateStr).getTime() / 1000)
const tableData = ref<SubscriptionPlan[]>([])
const tableLoading = ref(false)
const userInfoModalVisible = ref(false)
const userInfoLoading = ref(false)
const userInfoList = ref<UserInfoRecord[]>([])
const currentUserInfoPlanId = ref<string | number | null>(null)
const userInfoPage = reactive({
const tableData = ref<SubscriptionPlan[]>([])
const tableLoading = ref(false)
const userInfoModalVisible = ref(false)
const userInfoLoading = ref(false)
const userInfoList = ref<UserInfoRecord[]>([])
const currentUserInfoPlanId = ref<string | number | null>(null)
const userInfoPage = reactive({
current: 1,
size: 10,
total: 0
})
})
const modalVisible = ref(false)
const confirmLoading = ref(false)
const modalTitle = ref("New Subscription Plan")
const isEditMode = ref(false)
const formState = reactive({
const modalVisible = ref(false)
const confirmLoading = ref(false)
const modalTitle = ref("New Subscription Plan")
const isEditMode = ref(false)
const formState = reactive({
name: "",
currentPeriodStart: "",
currentPeriodEnd: "",
@@ -533,26 +533,26 @@ const formState = reactive({
accountNum: null as number | null,
status: undefined as PlanStatus | undefined,
countryOrRegion: null as string | null
})
})
const organizationModalVisible = ref(false)
const organizationForm = reactive({
const organizationModalVisible = ref(false)
const organizationForm = reactive({
name: "",
type: undefined as string | undefined
})
})
const statusLabelMap: Record<PlanStatus, string> = {
const statusLabelMap: Record<PlanStatus, string> = {
PENDING: "Pending",
ACTIVE: "Active",
EXPIRED: "Expired"
}
const statusColorMap: Record<PlanStatus, string> = {
}
const statusColorMap: Record<PlanStatus, string> = {
PENDING: "blue",
ACTIVE: "green",
EXPIRED: "red"
}
}
const statusOption = ref([
const statusOption = ref([
{
label: "Pending",
value: "PENDING"
@@ -565,27 +565,27 @@ const statusOption = ref([
label: "Expired",
value: "EXPIRED"
}
])
])
const disabledDate = (current: Dayjs) => {
const disabledDate = (current: Dayjs) => {
return current && current < dayjs().subtract(1, "days").endOf("day")
}
}
const disableEndDate = (current: Dayjs) => {
const disableEndDate = (current: Dayjs) => {
if (isEditMode.value) {
const specificTime = dayjs(formState.currentPeriodEnd)
return current && current < dayjs(formState.currentPeriodEnd * 1000).startOf("day")
}
return disabledDate(current)
}
const range = (start: number, end: number) => {
}
const range = (start: number, end: number) => {
const result = []
for (let i = start; i < end; i++) {
result.push(i)
}
return result
}
const disableEndTime = (date) => {
}
const disableEndTime = (date) => {
if (!formState.currentPeriodEnd || !isEditMode.value)
return {
disabledHours: () => [],
@@ -623,17 +623,17 @@ const disableEndTime = (date) => {
disabledMinutes: () => [],
disabledSeconds: () => []
}
}
}
const normalizeStatus = (status?: string): PlanStatus | undefined => {
const normalizeStatus = (status?: string): PlanStatus | undefined => {
if (!status) return undefined
const upper = status.toUpperCase() as PlanStatus
return upper
}
const getStatusColor = (status?: string) =>
}
const getStatusColor = (status?: string) =>
statusColorMap[normalizeStatus(status) as PlanStatus] || "default"
const columns = [
const columns = [
{ title: "Name", dataIndex: "name", key: "name", align: "center", width: 180 },
{ title: "ID", dataIndex: "id", key: "id", align: "center", width: 80 },
{
@@ -690,9 +690,9 @@ const columns = [
width: 120
},
{ title: "Operations", key: "actions", width: 160, align: "center", fixed: "right" }
]
]
const userInfoColumns = [
const userInfoColumns = [
{ title: "User Id", dataIndex: "id", key: "id", align: "center", width: 100 },
{
title: "Email",
@@ -747,23 +747,23 @@ const userInfoColumns = [
align: "center",
width: 120
}
]
]
const systemUserLabelMap: Record<string, string> = {
const systemUserLabelMap: Record<string, string> = {
"0": "visitor",
"1": "yearly",
"2": "monthly",
"3": "trial",
"4": "userInEvent",
"7": "Edu Admin"
}
}
const getSystemUserLabel = (systemUser?: number | string) => {
const getSystemUserLabel = (systemUser?: number | string) => {
if (systemUser === undefined || systemUser === null) return ""
return systemUserLabelMap[String(systemUser)] || String(systemUser)
}
}
const formatUserTime = (value?: number | string) => {
const formatUserTime = (value?: number | string) => {
if (!value) return ""
if (typeof value === "number") {
return formatTime(value / 1000, "YYYY-MM-DD hh:mm:ss")
@@ -772,16 +772,16 @@ const formatUserTime = (value?: number | string) => {
return formatTime(Number(value) / 1000, "YYYY-MM-DD hh:mm:ss")
}
return value
}
}
const normalizeUserInfoList = (res: any): UserInfoRecord[] => {
const normalizeUserInfoList = (res: any): UserInfoRecord[] => {
if (Array.isArray(res)) return res
if (Array.isArray(res?.records)) return res.records
if (res) return [res]
return []
}
}
const buildUserInfoParams = (id: string | number) => ({
const buildUserInfoParams = (id: string | number) => ({
endTime: "",
startTime: "",
size: userInfoPage.size,
@@ -796,9 +796,9 @@ const buildUserInfoParams = (id: string | number) => ({
orderBy: "",
userName: "",
subscriptionPlanId: id
})
})
const fetchUserInfo = async () => {
const fetchUserInfo = async () => {
if (currentUserInfoPlanId.value === null) return
userInfoLoading.value = true
userInfoList.value = []
@@ -817,9 +817,9 @@ const fetchUserInfo = async () => {
} finally {
userInfoLoading.value = false
}
}
}
const openUserInfo = async (record: SubscriptionPlan) => {
const openUserInfo = async (record: SubscriptionPlan) => {
console.log(record)
// debugger
@@ -827,15 +827,15 @@ const openUserInfo = async (record: SubscriptionPlan) => {
userInfoPage.current = 1
userInfoModalVisible.value = true
await fetchUserInfo()
}
}
const changeUserInfoPage = (pagination: any) => {
const changeUserInfoPage = (pagination: any) => {
userInfoPage.current = pagination.current
userInfoPage.size = pagination.pageSize
fetchUserInfo()
}
}
const customPlanRow = (record: SubscriptionPlan) => {
const customPlanRow = (record: SubscriptionPlan) => {
return {
onClick: (event: MouseEvent) => {
const target = event.target as HTMLElement | null
@@ -843,19 +843,19 @@ const customPlanRow = (record: SubscriptionPlan) => {
openUserInfo(record)
}
}
}
}
const historyTable = ref<HTMLElement | null>(null)
const historyTableHeight = ref(0)
const minTableBodyHeight = 120
let tableResizeObserver: ResizeObserver | null = null
let tableResizeTimer: ReturnType<typeof window.setTimeout> | null = null
const historyTable = ref<HTMLElement | null>(null)
const historyTableHeight = ref(0)
const minTableBodyHeight = 120
let tableResizeObserver: ResizeObserver | null = null
let tableResizeTimer: ReturnType<typeof window.setTimeout> | null = null
const handleResizeColumn = (w: any, col: any) => {
const handleResizeColumn = (w: any, col: any) => {
col.width = w
}
}
const getElementOuterHeight = (element: Element | null) => {
const getElementOuterHeight = (element: Element | null) => {
if (!element) return 0
const htmlElement = element as HTMLElement
const style = window.getComputedStyle(htmlElement)
@@ -864,9 +864,9 @@ const getElementOuterHeight = (element: Element | null) => {
Number.parseFloat(style.marginTop || "0") +
Number.parseFloat(style.marginBottom || "0")
)
}
}
const calculateTableHeight = () => {
const calculateTableHeight = () => {
if (tableResizeTimer) {
window.clearTimeout(tableResizeTimer)
}
@@ -891,13 +891,13 @@ const calculateTableHeight = () => {
tableResizeTimer = null
})
}, 50)
}
}
const handleResize = () => {
const handleResize = () => {
calculateTableHeight()
}
}
const setupTableResizeObserver = () => {
const setupTableResizeObserver = () => {
if (!historyTable.value || typeof ResizeObserver === "undefined") return
tableResizeObserver?.disconnect()
tableResizeObserver = new ResizeObserver(() => {
@@ -911,9 +911,9 @@ const setupTableResizeObserver = () => {
if (searchCard) {
tableResizeObserver.observe(searchCard)
}
}
}
onMounted(async () => {
onMounted(async () => {
await getOrganizationList()
await handleSearch()
calculateTableHeight()
@@ -921,22 +921,22 @@ onMounted(async () => {
window.addEventListener("resize", handleResize)
const list = sessionStorage.getItem("allCountry")
countryList.value = list ? JSON.parse(list) : []
})
})
onActivated(() => {
onActivated(() => {
calculateTableHeight()
})
})
onBeforeUnmount(() => {
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize)
tableResizeObserver?.disconnect()
if (tableResizeTimer) {
window.clearTimeout(tableResizeTimer)
tableResizeTimer = null
}
})
})
const handleFetchTableData = async () => {
const handleFetchTableData = async () => {
tableLoading.value = true
return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm)
.then((res) => {
@@ -947,9 +947,9 @@ const handleFetchTableData = async () => {
tableLoading.value = false
calculateTableHeight()
})
}
}
const resetFormState = () => {
const resetFormState = () => {
formState.name = ""
formState.currentPeriodStart = ""
formState.currentPeriodEnd = ""
@@ -959,20 +959,20 @@ const resetFormState = () => {
formState.accountNum = null
formState.status = undefined
formState.countryOrRegion = null
}
}
const changePage = (pagination: any) => {
const changePage = (pagination: any) => {
searchForm.page = pagination.current
searchForm.size = pagination.pageSize
handleFetchTableData()
}
}
const handleSearch = () => {
const handleSearch = () => {
searchForm.page = 1
handleFetchTableData()
}
}
const handleReset = () => {
const handleReset = () => {
searchForm.name = ""
searchForm.startTime = ""
searchForm.endTime = ""
@@ -982,16 +982,16 @@ const handleReset = () => {
searchForm.id = ""
searchForm.countryOrRegion = null
handleSearch()
}
}
const openCreate = () => {
const openCreate = () => {
modalTitle.value = "New Subscription Plan"
isEditMode.value = false
resetFormState()
modalVisible.value = true
}
}
const openEdit = (record: SubscriptionPlan) => {
const openEdit = (record: SubscriptionPlan) => {
modalTitle.value = "Edit Subscription Plan"
isEditMode.value = true
formState.name = record.name
@@ -1009,7 +1009,8 @@ const openEdit = (record: SubscriptionPlan) => {
if (record.organizationId) {
const orgExists = organizationOptions.value.some(
(org: any) =>
org.id === record.organizationId || String(org.id) === String(record.organizationId)
org.id === record.organizationId ||
String(org.id) === String(record.organizationId)
)
if (!orgExists) {
const orgName = (record as any).organizationName
@@ -1034,9 +1035,9 @@ const openEdit = (record: SubscriptionPlan) => {
})
})
}
}
}
const validateForm = (): boolean => {
const validateForm = (): boolean => {
interface FieldRule {
value: any
message: string
@@ -1077,9 +1078,9 @@ const validateForm = (): boolean => {
}
return true
}
}
const handleSubmit = async () => {
const handleSubmit = async () => {
if (!validateForm()) return
confirmLoading.value = true
const params = {
@@ -1107,21 +1108,21 @@ const handleSubmit = async () => {
isEditMode.value = false
handleSearch()
}
}
}
// 防抖包装,避免重复点击
const handleSubmitDebounced = debounce(handleSubmit, 500, {
// 防抖包装,避免重复点击
const handleSubmitDebounced = debounce(handleSubmit, 500, {
leading: true,
trailing: false
})
})
const cancelModal = () => {
const cancelModal = () => {
modalVisible.value = false
resetFormState()
isEditMode.value = false
}
}
const removePlan = (id: number) => {
const removePlan = (id: number) => {
tableLoading.value = true
Https.axiosGet(Https.httpUrls.deleteSubscribePlan, { params: { id } })
.then((res) => {
@@ -1135,16 +1136,16 @@ const removePlan = (id: number) => {
.finally(() => {
tableLoading.value = false
})
}
}
const organizationOptions = ref([])
const organizationParams = reactive({
const organizationOptions = ref([])
const organizationParams = reactive({
page: 1,
size: 10,
total: 0
})
const organizationLoading = ref(false)
const getOrganizationList = async (isLoadMore = false) => {
})
const organizationLoading = ref(false)
const getOrganizationList = async (isLoadMore = false) => {
if (organizationLoading.value) return
if (isLoadMore) {
const loaded = organizationParams.page * organizationParams.size
@@ -1179,17 +1180,17 @@ const getOrganizationList = async (isLoadMore = false) => {
} finally {
organizationLoading.value = false
}
}
const handleOrganizationScroll = (e: any) => {
}
const handleOrganizationScroll = (e: any) => {
const target = e?.target
if (!target) return
const nearBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 20
if (nearBottom) {
getOrganizationList(true)
}
}
}
const handleOrganizationSelect = (value: string) => {
const handleOrganizationSelect = (value: string) => {
if (value === "ADD_ORGANIZATION") {
// 打开添加组织弹窗
organizationModalVisible.value = true
@@ -1203,9 +1204,9 @@ const handleOrganizationSelect = (value: string) => {
}
})
}
}
}
const handleOrganizationChange = (value: string) => {
const handleOrganizationChange = (value: string) => {
// 如果change事件触发时值是"添加组织",立即重置
if (value === "ADD_ORGANIZATION") {
nextTick(() => {
@@ -1217,15 +1218,15 @@ const handleOrganizationChange = (value: string) => {
}
})
}
}
}
const cancelOrganizationModal = () => {
const cancelOrganizationModal = () => {
organizationModalVisible.value = false
organizationForm.name = ""
organizationForm.type = undefined
}
}
const handleCreateOrganization = async () => {
const handleCreateOrganization = async () => {
if (!organizationForm.name || !organizationForm.type) {
message.warning("Please fill in name and type")
return
@@ -1252,17 +1253,17 @@ const handleCreateOrganization = async () => {
message.error(error.message || "Failed to create organization")
console.error(error)
}
}
}
const filterOption = (input: string, option: any) => {
const filterOption = (input: string, option: any) => {
const label = option?.label ?? option?.children ?? option?.key?.label ?? ""
return String(label).toLowerCase().includes(input.toLowerCase())
}
}
</script>
<style lang="less" scoped>
.subscription-plan {
padding: 2rem 2.4rem 3.2rem 0;
.subscription-plan {
padding: 2rem 2.4rem 0 0;
display: flex;
height: 100%;
min-height: 0;
@@ -1285,7 +1286,7 @@ const filterOption = (input: string, option: any) => {
display: flex;
flex-direction: column;
overflow: hidden;
padding: 2.4rem;
padding: 2.4rem 2.4rem 0;
min-height: 0;
}
@@ -1364,15 +1365,15 @@ const filterOption = (input: string, option: any) => {
cursor: default;
}
}
}
}
.user-info-modal {
.user-info-modal {
:deep(.ant-modal-body) {
padding: 2.4rem;
}
}
}
:deep(.subscriptionPlan_modal) {
:deep(.subscriptionPlan_modal) {
.ant-modal-body {
// height: calc(65rem * 1.2);
display: flex;
@@ -1380,9 +1381,9 @@ const filterOption = (input: string, option: any) => {
padding: 2.5rem 3rem;
position: relative;
}
}
}
.subscriptionPlan_modal {
.subscriptionPlan_modal {
.form_content {
width: 100%;
display: flex;
@@ -1420,9 +1421,9 @@ const filterOption = (input: string, option: any) => {
margin-bottom: 0;
}
}
}
}
:deep(.search-form) {
:deep(.search-form) {
--search-label-width: 14rem;
--search-control-width: 20rem;
align-items: flex-start;
@@ -1466,15 +1467,15 @@ const filterOption = (input: string, option: any) => {
max-width: none;
}
}
}
}
@media (min-width: 1600px) {
@media (min-width: 1600px) {
:deep(.search-form) {
--search-control-width: 22rem;
}
}
}
@media (max-width: 760px) {
@media (max-width: 760px) {
:deep(.search-form) {
.ant-form-item {
flex: 1 1 100%;
@@ -1486,9 +1487,9 @@ const filterOption = (input: string, option: any) => {
max-width: calc(100% - var(--search-label-width));
}
}
}
}
:deep(.ant-select-dropdown) {
:deep(.ant-select-dropdown) {
.add-organization-option {
color: #1890ff !important;
font-weight: 600;
@@ -1501,9 +1502,9 @@ const filterOption = (input: string, option: any) => {
background-color: #e6f4ff !important;
}
}
}
}
:deep(.organization_modal) {
:deep(.organization_modal) {
.ant-modal-body {
height: auto;
min-height: 300px;
@@ -1523,13 +1524,13 @@ const filterOption = (input: string, option: any) => {
.modal_title_text {
margin-bottom: 1.5rem;
}
}
.organization_footer {
}
.organization_footer {
display: flex;
justify-content: flex-end;
column-gap: 3rem;
.footer_btn {
border-radius: 3.3rem;
}
}
}
</style>