|
|
@@ -0,0 +1,726 @@
|
|
|
+<template>
|
|
|
+ <div class="user-share-view">
|
|
|
+ <!-- 统计信息 -->
|
|
|
+ <div class="stats-section" v-if="statistics">
|
|
|
+ <div class="stats-grid">
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">
|
|
|
+ <i class="pi pi-share-alt"></i>
|
|
|
+ </div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ statistics.totalShares || 0 }}</div>
|
|
|
+ <div class="stat-label">总分享数</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">
|
|
|
+ <i class="pi pi-check-circle"></i>
|
|
|
+ </div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ statistics.successShares || 0 }}</div>
|
|
|
+ <div class="stat-label">成功分享</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">
|
|
|
+ <i class="pi pi-calendar"></i>
|
|
|
+ </div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ statistics.todayShares || 0 }}</div>
|
|
|
+ <div class="stat-label">今日分享</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">
|
|
|
+ <i class="pi pi-gift"></i>
|
|
|
+ </div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ statistics.rewardCount || 0 }}</div>
|
|
|
+ <div class="stat-label">奖励发放</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 数据表格 -->
|
|
|
+ <div class="rounded-lg p-4 bg-[var(--p-content-background)]">
|
|
|
+ <DataTable
|
|
|
+ :value="tableData.content || []"
|
|
|
+ :loading="loading"
|
|
|
+ :paginator="true"
|
|
|
+ :rows="tableData.metadata?.size || 20"
|
|
|
+ :totalRecords="tableData.metadata?.total || 0"
|
|
|
+ :lazy="true"
|
|
|
+ @page="handlePageChange"
|
|
|
+ :sortField="sortField"
|
|
|
+ :sortOrder="sortOrder"
|
|
|
+ @sort="handleSort"
|
|
|
+ paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
|
|
|
+ :rowsPerPageOptions="[10, 20, 50, 100]"
|
|
|
+ currentPageReportTemplate="显示 {first} 到 {last} 条,共 {totalRecords} 条记录"
|
|
|
+ responsiveLayout="scroll"
|
|
|
+ class="p-datatable-sm"
|
|
|
+ :first="(tableData.metadata?.page || 0) * (tableData.metadata?.size || 20)"
|
|
|
+ >
|
|
|
+ <template #header>
|
|
|
+ <div class="flex flex-wrap items-center gap-2">
|
|
|
+ <Calendar
|
|
|
+ v-model="filters.startDate"
|
|
|
+ dateFormat="yy-mm-dd"
|
|
|
+ placeholder="开始日期"
|
|
|
+ showIcon
|
|
|
+ size="small"
|
|
|
+ class="w-32"
|
|
|
+ :maxDate="filters.endDate"
|
|
|
+ />
|
|
|
+ <Calendar
|
|
|
+ v-model="filters.endDate"
|
|
|
+ dateFormat="yy-mm-dd"
|
|
|
+ placeholder="结束日期"
|
|
|
+ showIcon
|
|
|
+ size="small"
|
|
|
+ class="w-32"
|
|
|
+ :minDate="filters.startDate"
|
|
|
+ />
|
|
|
+ <InputText
|
|
|
+ v-model="filters.inviterName"
|
|
|
+ placeholder="邀请者用户名"
|
|
|
+ size="small"
|
|
|
+ class="w-32"
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
+ />
|
|
|
+ <Dropdown
|
|
|
+ v-model="filters.teamId"
|
|
|
+ :options="teamOptions"
|
|
|
+ optionLabel="name"
|
|
|
+ optionValue="id"
|
|
|
+ placeholder="选择团队"
|
|
|
+ showClear
|
|
|
+ size="small"
|
|
|
+ class="w-32"
|
|
|
+ />
|
|
|
+ <Dropdown
|
|
|
+ v-model="filters.status"
|
|
|
+ :options="statusOptions"
|
|
|
+ optionLabel="label"
|
|
|
+ optionValue="value"
|
|
|
+ placeholder="选择状态"
|
|
|
+ showClear
|
|
|
+ size="small"
|
|
|
+ class="w-32"
|
|
|
+ />
|
|
|
+ <Button
|
|
|
+ icon="pi pi-search"
|
|
|
+ @click="handleSearch"
|
|
|
+ label="搜索"
|
|
|
+ size="small"
|
|
|
+ severity="secondary"
|
|
|
+ :loading="loading"
|
|
|
+ />
|
|
|
+ <Button
|
|
|
+ icon="pi pi-refresh"
|
|
|
+ @click="handleReset"
|
|
|
+ label="重置"
|
|
|
+ size="small"
|
|
|
+ />
|
|
|
+ <Button
|
|
|
+ icon="pi pi-download"
|
|
|
+ @click="handleExport"
|
|
|
+ label="导出"
|
|
|
+ size="small"
|
|
|
+ severity="success"
|
|
|
+ :disabled="!tableData.content?.length"
|
|
|
+ />
|
|
|
+ <div class="flex-1"></div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <Column field="id" header="ID" :sortable="true" style="width: 80px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <span class="font-mono">{{ data.id }}</span>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column field="inviterName" header="分享者" :sortable="true" style="width: 120px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <div class="user-info">
|
|
|
+ <div class="user-name">{{ data.inviterName || '未知用户' }}</div>
|
|
|
+ <div class="user-id">ID: {{ data.inviterId }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column field="teamName" header="团队" :sortable="true" style="width: 120px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <div class="team-info" v-if="data.teamName">
|
|
|
+ <div class="team-name">{{ data.teamName }}</div>
|
|
|
+ <div class="team-id">ID: {{ data.teamId }}</div>
|
|
|
+ </div>
|
|
|
+ <span v-else class="text-muted">无团队</span>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column field="resourceId" header="资源ID" :sortable="true" style="width: 150px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <span class="font-mono">{{ data.resourceId }}</span>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column field="status" header="状态" :sortable="true" style="width: 100px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <Tag
|
|
|
+ :value="data.status ? '成功' : '失败'"
|
|
|
+ :severity="data.status ? 'success' : 'danger'"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column field="invitedUserIp" header="IP地址" style="width: 120px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <span class="font-mono">{{ data.invitedUserIp || '-' }}</span>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column field="createdAt" header="分享时间" :sortable="true" style="width: 150px">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <span>{{ formatDate(data.createdAt) }}</span>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ <Column header="操作" style="width: 120px" :frozen="true" alignFrozen="right">
|
|
|
+ <template #body="{ data }">
|
|
|
+ <div class="action-buttons">
|
|
|
+ <Button
|
|
|
+ icon="pi pi-eye"
|
|
|
+ size="small"
|
|
|
+ severity="info"
|
|
|
+ text
|
|
|
+ @click="viewDetails(data)"
|
|
|
+ v-tooltip.top="'查看详情'"
|
|
|
+ />
|
|
|
+ <Button
|
|
|
+ icon="pi pi-trash"
|
|
|
+ size="small"
|
|
|
+ severity="danger"
|
|
|
+ text
|
|
|
+ @click="deleteRecord(data)"
|
|
|
+ v-tooltip.top="'删除记录'"
|
|
|
+ v-if="userStore.userInfo.role === 'admin'"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </Column>
|
|
|
+ </DataTable>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 详情对话框 -->
|
|
|
+ <Dialog
|
|
|
+ v-model:visible="detailDialog.visible"
|
|
|
+ :header="`分享记录详情 - #${detailDialog.data?.id}`"
|
|
|
+ :style="{ width: '600px' }"
|
|
|
+ :modal="true"
|
|
|
+ >
|
|
|
+ <div v-if="detailDialog.data" class="detail-content">
|
|
|
+ <div class="detail-section">
|
|
|
+ <h4>基本信息</h4>
|
|
|
+ <div class="detail-grid">
|
|
|
+ <div class="detail-item">
|
|
|
+ <label>记录ID</label>
|
|
|
+ <span>{{ detailDialog.data.id }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-item">
|
|
|
+ <label>分享者</label>
|
|
|
+ <span>{{ detailDialog.data.inviterName || '未知用户' }} (ID: {{ detailDialog.data.inviterId }})</span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-item" v-if="detailDialog.data.teamName">
|
|
|
+ <label>团队</label>
|
|
|
+ <span>{{ detailDialog.data.teamName }} (ID: {{ detailDialog.data.teamId }})</span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-item">
|
|
|
+ <label>资源ID</label>
|
|
|
+ <span class="font-mono">{{ detailDialog.data.resourceId }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-item">
|
|
|
+ <label>状态</label>
|
|
|
+ <Tag
|
|
|
+ :value="detailDialog.data.status ? '成功' : '失败'"
|
|
|
+ :severity="detailDialog.data.status ? 'success' : 'danger'"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="detail-item">
|
|
|
+ <label>IP地址</label>
|
|
|
+ <span class="font-mono">{{ detailDialog.data.invitedUserIp || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="detail-item">
|
|
|
+ <label>分享时间</label>
|
|
|
+ <span>{{ formatDate(detailDialog.data.createdAt) }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, onMounted, computed } from 'vue'
|
|
|
+import { useToast } from 'primevue/usetoast'
|
|
|
+import { useUserStore } from '@/stores/user'
|
|
|
+import { useTeamStore } from '@/stores/team'
|
|
|
+import Button from 'primevue/button'
|
|
|
+import DataTable from 'primevue/datatable'
|
|
|
+import Column from 'primevue/column'
|
|
|
+import Tag from 'primevue/tag'
|
|
|
+import Calendar from 'primevue/calendar'
|
|
|
+import InputText from 'primevue/inputtext'
|
|
|
+import Dropdown from 'primevue/dropdown'
|
|
|
+import Dialog from 'primevue/dialog'
|
|
|
+import {
|
|
|
+ listUserShareRecords,
|
|
|
+ getUserShareStatistics,
|
|
|
+ deleteUserShareRecord
|
|
|
+} from '@/services/api'
|
|
|
+
|
|
|
+const toast = useToast()
|
|
|
+const userStore = useUserStore()
|
|
|
+const teamStore = useTeamStore()
|
|
|
+
|
|
|
+// 响应式数据
|
|
|
+const loading = ref(false)
|
|
|
+const tableData = ref({
|
|
|
+ content: [],
|
|
|
+ metadata: {
|
|
|
+ page: 0,
|
|
|
+ size: 20,
|
|
|
+ total: 0
|
|
|
+ }
|
|
|
+})
|
|
|
+const statistics = ref(null)
|
|
|
+
|
|
|
+// 筛选条件
|
|
|
+const filters = reactive({
|
|
|
+ startDate: null,
|
|
|
+ endDate: null,
|
|
|
+ inviterName: '',
|
|
|
+ teamId: null,
|
|
|
+ status: null
|
|
|
+})
|
|
|
+
|
|
|
+// 排序信息
|
|
|
+const sortField = ref('createdAt')
|
|
|
+const sortOrder = ref(-1)
|
|
|
+
|
|
|
+// 状态选项
|
|
|
+const statusOptions = [
|
|
|
+ { label: '全部', value: null },
|
|
|
+ { label: '成功', value: true },
|
|
|
+ { label: '失败', value: false }
|
|
|
+]
|
|
|
+
|
|
|
+// 团队选项
|
|
|
+const teamOptions = computed(() => {
|
|
|
+ return teamStore.teams.map(team => ({
|
|
|
+ id: team.id,
|
|
|
+ name: team.name
|
|
|
+ }))
|
|
|
+})
|
|
|
+
|
|
|
+// 详情对话框
|
|
|
+const detailDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ data: null
|
|
|
+})
|
|
|
+
|
|
|
+// 格式化日期
|
|
|
+const formatDate = (dateString) => {
|
|
|
+ if (!dateString) return '-'
|
|
|
+ const date = new Date(dateString)
|
|
|
+ return date.toLocaleString('zh-CN', {
|
|
|
+ year: 'numeric',
|
|
|
+ month: '2-digit',
|
|
|
+ day: '2-digit',
|
|
|
+ hour: '2-digit',
|
|
|
+ minute: '2-digit',
|
|
|
+ second: '2-digit'
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 加载数据
|
|
|
+const loadData = async () => {
|
|
|
+ loading.value = true
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ page: tableData.value.metadata.page,
|
|
|
+ size: tableData.value.metadata.size,
|
|
|
+ sortField: sortField.value,
|
|
|
+ sortOrder: sortOrder.value
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加筛选条件
|
|
|
+ if (filters.startDate) {
|
|
|
+ params.startDate = filters.startDate.toISOString().split('T')[0]
|
|
|
+ }
|
|
|
+ if (filters.endDate) {
|
|
|
+ params.endDate = filters.endDate.toISOString().split('T')[0]
|
|
|
+ }
|
|
|
+ if (filters.inviterName) {
|
|
|
+ params.inviterName = filters.inviterName
|
|
|
+ }
|
|
|
+ if (filters.teamId) {
|
|
|
+ params.teamId = filters.teamId
|
|
|
+ }
|
|
|
+ if (filters.status !== null) {
|
|
|
+ params.status = filters.status
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为统计API创建单独的参数对象,不包含分页参数
|
|
|
+ const statsParams = {}
|
|
|
+ if (filters.startDate) {
|
|
|
+ statsParams.startDate = filters.startDate.toISOString().split('T')[0]
|
|
|
+ }
|
|
|
+ if (filters.endDate) {
|
|
|
+ statsParams.endDate = filters.endDate.toISOString().split('T')[0]
|
|
|
+ }
|
|
|
+ if (filters.inviterName) {
|
|
|
+ statsParams.inviterName = filters.inviterName
|
|
|
+ }
|
|
|
+ if (filters.teamId) {
|
|
|
+ statsParams.teamId = filters.teamId
|
|
|
+ }
|
|
|
+ if (filters.status !== null) {
|
|
|
+ statsParams.status = filters.status
|
|
|
+ }
|
|
|
+
|
|
|
+ const [recordsData, statsData] = await Promise.all([
|
|
|
+ listUserShareRecords(params),
|
|
|
+ getUserShareStatistics(statsParams)
|
|
|
+ ])
|
|
|
+
|
|
|
+ tableData.value = recordsData
|
|
|
+ statistics.value = statsData
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载数据失败:', error)
|
|
|
+ toast.add({
|
|
|
+ severity: 'error',
|
|
|
+ summary: '错误',
|
|
|
+ detail: '加载数据失败',
|
|
|
+ life: 3000
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ loading.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 搜索
|
|
|
+const handleSearch = () => {
|
|
|
+ tableData.value.metadata.page = 0
|
|
|
+ loadData()
|
|
|
+}
|
|
|
+
|
|
|
+// 重置筛选条件
|
|
|
+const handleReset = () => {
|
|
|
+ Object.assign(filters, {
|
|
|
+ startDate: null,
|
|
|
+ endDate: null,
|
|
|
+ inviterName: '',
|
|
|
+ teamId: null,
|
|
|
+ status: null
|
|
|
+ })
|
|
|
+ tableData.value.metadata.page = 0
|
|
|
+ loadData()
|
|
|
+}
|
|
|
+
|
|
|
+// 分页变化
|
|
|
+const handlePageChange = (event) => {
|
|
|
+ console.log('分页变化:', event)
|
|
|
+ tableData.value.metadata.page = event.page
|
|
|
+ tableData.value.metadata.size = event.rows
|
|
|
+ loadData()
|
|
|
+}
|
|
|
+
|
|
|
+// 排序变化
|
|
|
+const handleSort = (event) => {
|
|
|
+ sortField.value = event.sortField
|
|
|
+ sortOrder.value = event.sortOrder === 1 ? 1 : -1
|
|
|
+ loadData()
|
|
|
+}
|
|
|
+
|
|
|
+// 查看详情
|
|
|
+const viewDetails = (record) => {
|
|
|
+ detailDialog.data = record
|
|
|
+ detailDialog.visible = true
|
|
|
+}
|
|
|
+
|
|
|
+// 删除记录
|
|
|
+const deleteRecord = async (record) => {
|
|
|
+ if (!confirm(`确定要删除分享记录 #${record.id} 吗?`)) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await deleteUserShareRecord(record.id)
|
|
|
+ toast.add({
|
|
|
+ severity: 'success',
|
|
|
+ summary: '成功',
|
|
|
+ detail: '删除成功',
|
|
|
+ life: 2000
|
|
|
+ })
|
|
|
+ loadData()
|
|
|
+ } catch (error) {
|
|
|
+ console.error('删除失败:', error)
|
|
|
+ toast.add({
|
|
|
+ severity: 'error',
|
|
|
+ summary: '错误',
|
|
|
+ detail: '删除失败',
|
|
|
+ life: 3000
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 导出数据
|
|
|
+const handleExport = () => {
|
|
|
+ // TODO: 实现导出功能
|
|
|
+ toast.add({
|
|
|
+ severity: 'info',
|
|
|
+ summary: '提示',
|
|
|
+ detail: '导出功能开发中',
|
|
|
+ life: 2000
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+// 组件挂载时加载数据
|
|
|
+onMounted(() => {
|
|
|
+ loadData()
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.user-share-view {
|
|
|
+ padding: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.page-header {
|
|
|
+ margin-bottom: 2rem;
|
|
|
+}
|
|
|
+
|
|
|
+.page-title {
|
|
|
+ font-size: 1.5rem;
|
|
|
+ font-weight: 600;
|
|
|
+ margin: 0 0 0.5rem 0;
|
|
|
+ color: var(--p-text-color);
|
|
|
+}
|
|
|
+
|
|
|
+.page-description {
|
|
|
+ color: var(--p-text-color-secondary);
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-section {
|
|
|
+ margin-bottom: 1.5rem;
|
|
|
+}
|
|
|
+
|
|
|
+.stats-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
|
+ gap: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-card {
|
|
|
+ background: var(--p-surface-card);
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 1.5rem;
|
|
|
+ border: 1px solid var(--p-surface-border);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-icon {
|
|
|
+ width: 3rem;
|
|
|
+ height: 3rem;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: var(--p-primary-100);
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: var(--p-primary-600);
|
|
|
+ font-size: 1.25rem;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-content {
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-value {
|
|
|
+ font-size: 1.5rem;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--p-text-color);
|
|
|
+ line-height: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.stat-label {
|
|
|
+ color: var(--p-text-color-secondary);
|
|
|
+ font-size: 0.875rem;
|
|
|
+ margin-top: 0.25rem;
|
|
|
+}
|
|
|
+
|
|
|
+.table-section {
|
|
|
+ background: var(--p-surface-card);
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid var(--p-surface-border);
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.user-info {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 0.25rem;
|
|
|
+}
|
|
|
+
|
|
|
+.user-name {
|
|
|
+ font-weight: 500;
|
|
|
+ color: var(--p-text-color);
|
|
|
+}
|
|
|
+
|
|
|
+.user-id {
|
|
|
+ font-size: 0.75rem;
|
|
|
+ color: var(--p-text-color-secondary);
|
|
|
+}
|
|
|
+
|
|
|
+.team-info {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 0.25rem;
|
|
|
+}
|
|
|
+
|
|
|
+.team-name {
|
|
|
+ font-weight: 500;
|
|
|
+ color: var(--p-text-color);
|
|
|
+}
|
|
|
+
|
|
|
+.team-id {
|
|
|
+ font-size: 0.75rem;
|
|
|
+ color: var(--p-text-color-secondary);
|
|
|
+}
|
|
|
+
|
|
|
+.action-buttons {
|
|
|
+ display: flex;
|
|
|
+ gap: 0.25rem;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-content {
|
|
|
+ padding: 1rem 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-section {
|
|
|
+ margin-bottom: 1.5rem;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-section h4 {
|
|
|
+ margin: 0 0 1rem 0;
|
|
|
+ color: var(--p-text-color);
|
|
|
+ font-size: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
|
+ gap: 1rem;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-item {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 0.25rem;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-item label {
|
|
|
+ font-weight: 500;
|
|
|
+ color: var(--p-text-color-secondary);
|
|
|
+ font-size: 0.875rem;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-item span {
|
|
|
+ color: var(--p-text-color);
|
|
|
+}
|
|
|
+
|
|
|
+.text-muted {
|
|
|
+ color: var(--p-text-color-secondary);
|
|
|
+}
|
|
|
+
|
|
|
+.font-mono {
|
|
|
+ font-family: 'Courier New', monospace;
|
|
|
+ font-size: 0.875rem;
|
|
|
+}
|
|
|
+
|
|
|
+/* 移动端响应式设计 */
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .user-share-view {
|
|
|
+ padding: 0.5rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-header {
|
|
|
+ margin-bottom: 1rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 1.25rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stats-grid {
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ gap: 0.75rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-card {
|
|
|
+ padding: 1rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .detail-grid {
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 移动端表格优化 */
|
|
|
+ .p-datatable {
|
|
|
+ font-size: 0.875rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .p-datatable .p-datatable-header {
|
|
|
+ padding: 0.5rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .p-datatable .p-datatable-tbody > tr > td {
|
|
|
+ padding: 0.5rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 移动端按钮优化 */
|
|
|
+ .action-buttons {
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 0.25rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .action-buttons .p-button {
|
|
|
+ width: 100%;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 小屏幕移动端进一步优化 */
|
|
|
+@media (max-width: 480px) {
|
|
|
+ .user-share-view {
|
|
|
+ padding: 0.25rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .page-title {
|
|
|
+ font-size: 1.125rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-card {
|
|
|
+ padding: 0.75rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-icon {
|
|
|
+ width: 2.5rem;
|
|
|
+ height: 2.5rem;
|
|
|
+ font-size: 1rem;
|
|
|
+ }
|
|
|
+
|
|
|
+ .stat-value {
|
|
|
+ font-size: 1.25rem;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|