|
@@ -0,0 +1,558 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="rounded-lg p-4 bg-[var(--p-content-background)]">
|
|
|
|
|
+ <DataTable
|
|
|
|
|
+ :value="tableData.content"
|
|
|
|
|
+ :paginator="true"
|
|
|
|
|
+ paginatorTemplate="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown JumpToPageInput"
|
|
|
|
|
+ currentPageReportTemplate="{totalRecords} 条记录 "
|
|
|
|
|
+ :rows="tableData.metadata.size"
|
|
|
|
|
+ :rowsPerPageOptions="[10, 20, 50, 100]"
|
|
|
|
|
+ :totalRecords="tableData.metadata.total"
|
|
|
|
|
+ @page="handlePageChange"
|
|
|
|
|
+ lazy
|
|
|
|
|
+ scrollable
|
|
|
|
|
+ class="members-table"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #header>
|
|
|
|
|
+ <div class="flex flex-wrap items-center gap-2">
|
|
|
|
|
+ <InputText v-model="searchForm.id" placeholder="ID" size="small" class="w-32" @keyup.enter="handleSearch" />
|
|
|
|
|
+ <InputText
|
|
|
|
|
+ v-model="searchForm.name"
|
|
|
|
|
+ placeholder="成员名称"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="w-32"
|
|
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
|
|
+ />
|
|
|
|
|
+ <Select
|
|
|
|
|
+ v-model="searchForm.teamId"
|
|
|
|
|
+ :options="teamOptions"
|
|
|
|
|
+ optionLabel="label"
|
|
|
|
|
+ optionValue="value"
|
|
|
|
|
+ placeholder="选择团队"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="w-40"
|
|
|
|
|
+ showClear
|
|
|
|
|
+ />
|
|
|
|
|
+ <Button icon="pi pi-search" @click="handleSearch" label="搜索" size="small" severity="secondary" />
|
|
|
|
|
+ <Button icon="pi pi-refresh" @click="handleRefresh" label="刷新" size="small" />
|
|
|
|
|
+ <Button icon="pi pi-plus" @click="openAddDialog" label="新增成员" size="small" severity="success" />
|
|
|
|
|
+ <div class="flex-1"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
|
|
+ <Column field="id" header="ID" style="width: 80px" frozen>
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <span
|
|
|
|
|
+ class="font-mono text-sm copyable-text"
|
|
|
|
|
+ :title="slotProps.data.id"
|
|
|
|
|
+ @click="copyToClipboard(slotProps.data.id)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ slotProps.data.id }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+
|
|
|
|
|
+ <Column field="name" header="成员名称" style="min-width: 150px; max-width: 200px">
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <span
|
|
|
|
|
+ class="font-medium member-name-text copyable-text"
|
|
|
|
|
+ :title="slotProps.data.name"
|
|
|
|
|
+ @click="copyToClipboard(slotProps.data.name)"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ slotProps.data.name }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+
|
|
|
|
|
+ <Column field="teamId" header="所属团队" style="min-width: 120px">
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <span class="team-name-text font-medium">
|
|
|
|
|
+ {{ getTeamName(slotProps.data.teamId) }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+
|
|
|
|
|
+ <Column field="totalRevenue" header="总收入" style="min-width: 120px">
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <span class="total-revenue-text font-semibold"> {{ formatAmount(slotProps.data.totalRevenue) }} </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+
|
|
|
|
|
+ <Column field="todayRevenue" header="今日收入" style="min-width: 120px">
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <span class="today-revenue-text font-semibold"> {{ formatAmount(slotProps.data.todayRevenue) }} </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+
|
|
|
|
|
+ <Column field="createdAt" header="创建时间" style="min-width: 150px">
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <span class="text-sm">
|
|
|
|
|
+ {{ formatDateTime(slotProps.data.createdAt) }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+
|
|
|
|
|
+ <Column
|
|
|
|
|
+ header="操作"
|
|
|
|
|
+ style="min-width: 200px; width: 200px"
|
|
|
|
|
+ align-frozen="right"
|
|
|
|
|
+ frozen
|
|
|
|
|
+ :pt="{
|
|
|
|
|
+ columnHeaderContent: {
|
|
|
|
|
+ class: 'justify-center'
|
|
|
|
|
+ }
|
|
|
|
|
+ }"
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #body="slotProps">
|
|
|
|
|
+ <div class="flex justify-center gap-1">
|
|
|
|
|
+ <Button
|
|
|
|
|
+ icon="pi pi-pencil"
|
|
|
|
|
+ severity="info"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ text
|
|
|
|
|
+ rounded
|
|
|
|
|
+ aria-label="编辑"
|
|
|
|
|
+ @click="openEditDialog(slotProps.data)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <Button
|
|
|
|
|
+ icon="pi pi-trash"
|
|
|
|
|
+ severity="danger"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ text
|
|
|
|
|
+ rounded
|
|
|
|
|
+ aria-label="删除"
|
|
|
|
|
+ @click="confirmDelete(slotProps.data)"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Column>
|
|
|
|
|
+ </DataTable>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 新增/编辑弹窗 -->
|
|
|
|
|
+ <Dialog
|
|
|
|
|
+ v-model:visible="editDialog"
|
|
|
|
|
+ :modal="true"
|
|
|
|
|
+ :header="isEdit ? '编辑成员' : '新增成员'"
|
|
|
|
|
+ :style="{ width: '500px' }"
|
|
|
|
|
+ position="center"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="p-fluid">
|
|
|
|
|
+ <div class="field">
|
|
|
|
|
+ <label for="edit-name" class="font-medium text-sm mb-2 block">成员名称</label>
|
|
|
|
|
+ <InputText id="edit-name" v-model="editForm.name" class="w-full" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="field mt-4">
|
|
|
|
|
+ <label for="edit-teamId" class="font-medium text-sm mb-2 block">选择团队</label>
|
|
|
|
|
+ <Select
|
|
|
|
|
+ id="edit-teamId"
|
|
|
|
|
+ v-model="editForm.teamId"
|
|
|
|
|
+ :options="teamSelectOptions"
|
|
|
|
|
+ optionLabel="label"
|
|
|
|
|
+ optionValue="value"
|
|
|
|
|
+ placeholder="请选择团队"
|
|
|
|
|
+ class="w-full"
|
|
|
|
|
+ showClear
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="!isEdit" class="field mt-4">
|
|
|
|
|
+ <label for="edit-password" class="font-medium text-sm mb-2 block">密码</label>
|
|
|
|
|
+ <Password
|
|
|
|
|
+ id="edit-password"
|
|
|
|
|
+ v-model="editForm.password"
|
|
|
|
|
+ :feedback="false"
|
|
|
|
|
+ toggleMask
|
|
|
|
|
+ class="w-full"
|
|
|
|
|
+ placeholder="请输入密码"
|
|
|
|
|
+ inputClass="w-full"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="!isEdit" class="field mt-4">
|
|
|
|
|
+ <label for="edit-confirmPassword" class="font-medium text-sm mb-2 block">确认密码</label>
|
|
|
|
|
+ <Password
|
|
|
|
|
+ id="edit-confirmPassword"
|
|
|
|
|
+ v-model="editForm.confirmPassword"
|
|
|
|
|
+ :feedback="false"
|
|
|
|
|
+ toggleMask
|
|
|
|
|
+ class="w-full"
|
|
|
|
|
+ placeholder="请再次输入密码"
|
|
|
|
|
+ inputClass="w-full"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <div class="flex justify-end gap-3">
|
|
|
|
|
+ <Button label="取消" severity="secondary" @click="editDialog = false" />
|
|
|
|
|
+ <Button label="保存" severity="success" @click="saveEdit" :loading="editLoading" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </Dialog>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, onMounted, computed } from 'vue'
|
|
|
|
|
+import Button from 'primevue/button'
|
|
|
|
|
+import Column from 'primevue/column'
|
|
|
|
|
+import DataTable from 'primevue/datatable'
|
|
|
|
|
+import Dialog from 'primevue/dialog'
|
|
|
|
|
+import Select from 'primevue/select'
|
|
|
|
|
+import InputText from 'primevue/inputtext'
|
|
|
|
|
+import InputNumber from 'primevue/inputnumber'
|
|
|
|
|
+import Password from 'primevue/password'
|
|
|
|
|
+import { useConfirm } from 'primevue/useconfirm'
|
|
|
|
|
+import { useToast } from 'primevue/usetoast'
|
|
|
|
|
+import { listMembers, createMember, updateMember, deleteMember } from '@/services/api'
|
|
|
|
|
+import { useTeamStore } from '@/stores/team'
|
|
|
|
|
+
|
|
|
|
|
+const toast = useToast()
|
|
|
|
|
+const confirm = useConfirm()
|
|
|
|
|
+const teamStore = useTeamStore()
|
|
|
|
|
+
|
|
|
|
|
+// 团队选项(用于搜索)
|
|
|
|
|
+const teamOptions = computed(() => {
|
|
|
|
|
+ return [
|
|
|
|
|
+ { label: '全部团队', value: null },
|
|
|
|
|
+ ...teamStore.teams.map((team) => ({
|
|
|
|
|
+ label: team.name,
|
|
|
|
|
+ value: team.id
|
|
|
|
|
+ }))
|
|
|
|
|
+ ]
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 团队选项(用于新增/编辑,不包含全部团队)
|
|
|
|
|
+const teamSelectOptions = computed(() => {
|
|
|
|
|
+ return teamStore.teams.map((team) => ({
|
|
|
|
|
+ label: team.name,
|
|
|
|
|
+ value: team.id
|
|
|
|
|
+ }))
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 根据团队ID获取团队名称
|
|
|
|
|
+const getTeamName = (teamId) => {
|
|
|
|
|
+ if (!teamId) return '-'
|
|
|
|
|
+ const team = teamStore.teams.find((t) => t.id === teamId)
|
|
|
|
|
+ return team ? team.name : '-'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 根据团队ID获取团队的userId
|
|
|
|
|
+const getTeamUserId = (teamId) => {
|
|
|
|
|
+ if (!teamId) return null
|
|
|
|
|
+ const team = teamStore.teams.find((t) => t.id === teamId)
|
|
|
|
|
+ return team ? team.userId : null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 表格数据
|
|
|
|
|
+const tableData = ref({
|
|
|
|
|
+ content: [],
|
|
|
|
|
+ metadata: {
|
|
|
|
|
+ page: 0,
|
|
|
|
|
+ size: 20,
|
|
|
|
|
+ total: 0
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 加载状态
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+// 编辑相关
|
|
|
|
|
+const editDialog = ref(false)
|
|
|
|
|
+const editLoading = ref(false)
|
|
|
|
|
+const isEdit = ref(false)
|
|
|
|
|
+const editForm = ref({
|
|
|
|
|
+ id: null,
|
|
|
|
|
+ name: null,
|
|
|
|
|
+ teamId: null
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 搜索表单
|
|
|
|
|
+const searchForm = ref({
|
|
|
|
|
+ id: null,
|
|
|
|
|
+ name: null,
|
|
|
|
|
+ teamId: null
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 格式化金额
|
|
|
|
|
+const formatAmount = (amount) => {
|
|
|
|
|
+ if (!amount) return '0.00'
|
|
|
|
|
+ return Number(amount).toFixed(2)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 格式化日期时间
|
|
|
|
|
+const formatDateTime = (dateString) => {
|
|
|
|
|
+ if (!dateString) return '-'
|
|
|
|
|
+
|
|
|
|
|
+ const date = new Date(dateString)
|
|
|
|
|
+ const year = date.getFullYear()
|
|
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
|
|
|
+ const day = String(date.getDate()).padStart(2, '0')
|
|
|
|
|
+ const hours = String(date.getHours()).padStart(2, '0')
|
|
|
|
|
+ const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
|
|
|
+ const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
|
|
|
+
|
|
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取数据
|
|
|
|
|
+const fetchData = async () => {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await listMembers(
|
|
|
|
|
+ tableData.value.metadata.page,
|
|
|
|
|
+ tableData.value.metadata.size,
|
|
|
|
|
+ searchForm.value.name || undefined,
|
|
|
|
|
+ searchForm.value.teamId || undefined
|
|
|
|
|
+ )
|
|
|
|
|
+ tableData.value = response
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ toast.add({
|
|
|
|
|
+ severity: 'error',
|
|
|
|
|
+ summary: '错误',
|
|
|
|
|
+ detail: '获取成员列表失败',
|
|
|
|
|
+ life: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 分页处理
|
|
|
|
|
+const handlePageChange = (event) => {
|
|
|
|
|
+ tableData.value.metadata.page = event.page
|
|
|
|
|
+ tableData.value.metadata.size = event.rows
|
|
|
|
|
+ fetchData()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 搜索处理
|
|
|
|
|
+const handleSearch = () => {
|
|
|
|
|
+ tableData.value.metadata.page = 0
|
|
|
|
|
+ fetchData()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 刷新处理
|
|
|
|
|
+const handleRefresh = () => {
|
|
|
|
|
+ searchForm.value = {
|
|
|
|
|
+ id: null,
|
|
|
|
|
+ name: null,
|
|
|
|
|
+ teamId: null
|
|
|
|
|
+ }
|
|
|
|
|
+ tableData.value.metadata.page = 0
|
|
|
|
|
+ fetchData()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 确认删除
|
|
|
|
|
+const confirmDelete = (member) => {
|
|
|
|
|
+ confirm.require({
|
|
|
|
|
+ message: `确定要删除成员 "${member.name}" 吗?`,
|
|
|
|
|
+ header: '确认删除',
|
|
|
|
|
+ icon: 'pi pi-exclamation-triangle',
|
|
|
|
|
+ accept: () => deleteMemberRecord(member.id)
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 删除成员
|
|
|
|
|
+const deleteMemberRecord = async (id) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await deleteMember(id)
|
|
|
|
|
+ toast.add({
|
|
|
|
|
+ severity: 'success',
|
|
|
|
|
+ summary: '成功',
|
|
|
|
|
+ detail: '删除成功',
|
|
|
|
|
+ life: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ fetchData()
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ toast.add({
|
|
|
|
|
+ severity: 'error',
|
|
|
|
|
+ summary: '错误',
|
|
|
|
|
+ detail: '删除失败',
|
|
|
|
|
+ life: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 复制到剪贴板
|
|
|
|
|
+const copyToClipboard = async (text) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await navigator.clipboard.writeText(text)
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ const textArea = document.createElement('textarea')
|
|
|
|
|
+ textArea.value = text
|
|
|
|
|
+ document.body.appendChild(textArea)
|
|
|
|
|
+ textArea.select()
|
|
|
|
|
+ document.execCommand('copy')
|
|
|
|
|
+ document.body.removeChild(textArea)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 打开新增弹窗
|
|
|
|
|
+const openAddDialog = () => {
|
|
|
|
|
+ isEdit.value = false
|
|
|
|
|
+ editForm.value = {
|
|
|
|
|
+ id: null,
|
|
|
|
|
+ name: null,
|
|
|
|
|
+ teamId: null
|
|
|
|
|
+ }
|
|
|
|
|
+ editDialog.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 打开编辑弹窗
|
|
|
|
|
+const openEditDialog = (member) => {
|
|
|
|
|
+ isEdit.value = true
|
|
|
|
|
+ editForm.value = {
|
|
|
|
|
+ id: member.id,
|
|
|
|
|
+ name: member.name || null,
|
|
|
|
|
+ teamId: member.teamId || null
|
|
|
|
|
+ }
|
|
|
|
|
+ editDialog.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 保存编辑
|
|
|
|
|
+const saveEdit = async () => {
|
|
|
|
|
+ editLoading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 过滤掉空值参数
|
|
|
|
|
+ const formData = {}
|
|
|
|
|
+ if (editForm.value.name !== null && editForm.value.name !== '') {
|
|
|
|
|
+ formData.name = editForm.value.name
|
|
|
|
|
+ }
|
|
|
|
|
+ if (editForm.value.teamId !== null && editForm.value.teamId !== '') {
|
|
|
|
|
+ formData.teamId = editForm.value.teamId
|
|
|
|
|
+ // 使用选中团队的userId作为teamUserId
|
|
|
|
|
+ formData.teamUserId = getTeamUserId(editForm.value.teamId)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (isEdit.value) {
|
|
|
|
|
+ await updateMember(editForm.value.id, formData)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await createMember(formData)
|
|
|
|
|
+ }
|
|
|
|
|
+ toast.add({
|
|
|
|
|
+ severity: 'success',
|
|
|
|
|
+ summary: '成功',
|
|
|
|
|
+ detail: isEdit.value ? '更新成功' : '创建成功',
|
|
|
|
|
+ life: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ editDialog.value = false
|
|
|
|
|
+ fetchData()
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ toast.add({
|
|
|
|
|
+ severity: 'error',
|
|
|
|
|
+ summary: '错误',
|
|
|
|
|
+ detail: isEdit.value ? '更新失败' : '创建失败',
|
|
|
|
|
+ life: 3000
|
|
|
|
|
+ })
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ editLoading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 初始化
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ fetchData()
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+.p-datatable-sm .p-datatable-tbody > tr > td {
|
|
|
|
|
+ padding: 0.5rem;
|
|
|
|
|
+ vertical-align: top;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.p-datatable-sm .p-datatable-thead > tr > th {
|
|
|
|
|
+ padding: 0.5rem;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.members-table {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.members-table .p-datatable-wrapper {
|
|
|
|
|
+ overflow-x: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.members-table .p-datatable-thead th {
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ min-width: 100px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.font-mono {
|
|
|
|
|
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.member-name-text {
|
|
|
|
|
+ word-wrap: break-word;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ white-space: normal;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.team-name-text {
|
|
|
|
|
+ color: #7c3aed;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.team-id-text {
|
|
|
|
|
+ word-wrap: break-word;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ white-space: normal;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.user-id-text {
|
|
|
|
|
+ word-wrap: break-word;
|
|
|
|
|
+ word-break: break-all;
|
|
|
|
|
+ white-space: normal;
|
|
|
|
|
+ line-height: 1.4;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.total-revenue-text {
|
|
|
|
|
+ color: #2563eb;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.today-revenue-text {
|
|
|
|
|
+ color: #059669;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.font-medium {
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.text-sm {
|
|
|
|
|
+ font-size: 0.875rem;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.copyable-text {
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.2s ease;
|
|
|
|
|
+ user-select: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.copyable-text:hover {
|
|
|
|
|
+ background-color: #e5e7eb;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.copyable-text:active {
|
|
|
|
|
+ background-color: #d1d5db;
|
|
|
|
|
+ transform: scale(0.98);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Password组件样式修复 */
|
|
|
|
|
+.p-password {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.p-password .p-inputtext {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.p-password .p-password-input {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|