+
添加用户
@@ -399,6 +399,10 @@ const roleClubLabel = (role) => {
return `[${cname}] ${role.role_name || role.role_code || ''}`
}
+const canAddUser = computed(() => {
+ return canManageClubAssignments.value || manageableClubIds.value.length > 0
+})
+
const canManageRolesForClub = (clubId) => {
const cid = clubId || ''
if (canManageClubAssignments.value) return true
@@ -411,7 +415,7 @@ const visibleRolesForRow = (row) => {
return roles.filter((r) => manageableClubIds.value.includes(r.club_id || ''))
}
-// 权限状态
+// 权限状态:集团高管 / 俱乐部超管 / 000001 均可访问
const hasPermission = ref(true)
const canManageClubAssignments = ref(false)
const manageableClubIds = ref([])
@@ -605,6 +609,8 @@ const fetchUserList = async () => {
total.value = res.data.total || 0
canManageClubAssignments.value = !!res.data.can_manage_club_assignments
manageableClubIds.value = res.data.manageable_club_ids || []
+ } else if (res.code === 403) {
+ hasPermission.value = false
} else {
ElMessage.error(res.msg || '获取用户列表失败')
}
@@ -853,7 +859,7 @@ const confirmAddUser = async () => {
}
}
-// 初始化
+// 初始化:先拉用户列表(含 manageable_club_ids),再拉角色列表
onMounted(async () => {
if (!username) {
ElMessage.error('未获取到用户信息')
@@ -861,7 +867,9 @@ onMounted(async () => {
}
await loadClubOptions()
await fetchUserList()
- await fetchRoleList()
+ if (hasPermission.value) {
+ await fetchRoleList()
+ }
})
diff --git a/src/views/admin/Role.vue b/src/views/admin/Role.vue
index f7f1566..6c5475e 100644
--- a/src/views/admin/Role.vue
+++ b/src/views/admin/Role.vue
@@ -371,6 +371,7 @@ const removePermission = async (perm) => {
username,
action: 'remove_permission',
role_code: currentRole.value.role_code,
+ target_club_id: currentRole.value.club_id || '',
perm_code: perm.perm_code
})
if (res.code === 0) {
diff --git a/src/views/member/Data.vue b/src/views/member/Data.vue
index 369853c..4d4fe20 100644
--- a/src/views/member/Data.vue
+++ b/src/views/member/Data.vue
@@ -526,7 +526,7 @@ onMounted(fetchData)
}
.member-data-table :deep(.el-table td.el-table__cell) {
background: rgba(12, 18, 28, 0.55) !important;
- color: #d8ebff !important;
+ color: #ffffff !important;
border-bottom: 1px solid rgba(64, 158, 255, 0.1) !important;
}
.member-data-table :deep(.el-table__body tr:hover > td.el-table__cell) {
diff --git a/src/views/miniapp/RankReward.vue b/src/views/miniapp/RankReward.vue
index 329cb0e..c2c756a 100644
--- a/src/views/miniapp/RankReward.vue
+++ b/src/views/miniapp/RankReward.vue
@@ -18,7 +18,7 @@
@@ -53,6 +53,12 @@
+
+
+
+
+
+
@@ -151,6 +157,8 @@ const form = reactive({
sort_field: 'chengjiao_zongliang',
min_metric: 0,
claim_days: 30,
+ activity_start: '',
+ activity_end: '',
description: '',
tiers: [{ rank_from: 1, rank_to: 1, reward_amount: 0, label: '冠军' }],
})
@@ -184,6 +192,8 @@ const selectScheme = () => {
sort_field: hit.sort_field || defaults,
min_metric: hit.min_metric || 0,
claim_days: hit.claim_days || 30,
+ activity_start: hit.activity_start || '',
+ activity_end: hit.activity_end || '',
description: hit.description || '',
tiers: hit.tiers?.length
? hit.tiers.map((t) => ({ ...t, reward_amount: Number(t.reward_amount) }))
@@ -196,6 +206,8 @@ const selectScheme = () => {
sort_field: defaults,
min_metric: 0,
claim_days: 30,
+ activity_start: '',
+ activity_end: '',
description: '',
tiers: [{ rank_from: 1, rank_to: 1, reward_amount: 0, label: '冠军' }],
})
diff --git a/src/views/punishment/components/FadanDetail.vue b/src/views/punishment/components/FadanDetail.vue
index f78c486..f1c66ff 100644
--- a/src/views/punishment/components/FadanDetail.vue
+++ b/src/views/punishment/components/FadanDetail.vue
@@ -7,7 +7,7 @@
{{ fadan.shenfen_text }}
¥{{ fadan.fakuanjine }}
- {{ statusText(fadan.zhuangtai) }}
+ {{ statusText(fadan) }}
{{ fadan.yingxiang_qiangdan ? '是' : '否' }}
{{ fadan.chufaliyou }}
@@ -36,8 +36,14 @@
-
-
+
+
+ 同意审核(进入待缴纳/申诉流程)
+ 驳回申请
+
+
+
+
同意申诉(驳回处罚)
拒绝申诉
@@ -48,7 +54,7 @@
-
+
import { ref, computed, watch } from 'vue'
-import { ElMessage, ElMessageBox } from 'element-plus'
+import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
+import request from '@/utils/request'
import { uploadFiles } from '@/utils/upload'
import { JITUAN_API } from '@/utils/club-context'
+import { rowPenaltyStatusText, rowPenaltyStatusType, isPlatformAuditPending } from '@/utils/penalty-status'
const props = defineProps({
visible: Boolean,
@@ -90,16 +98,20 @@ const ossUrl = window.$ossURL || ''
const fullZhengjuUrls = computed(() => (props.fadan?.zhengju_tupian || []).map(url => ossUrl + url))
const fullShensuUrls = computed(() => (props.fadan?.shensu_tupian || []).map(url => ossUrl + url))
-// 处理表单
const actionDialog = ref(false)
const actionTitle = ref('')
const currentAction = ref('')
+const isPlatformAction = ref(false)
const reason = ref('')
const fileList = ref([])
const selectedFiles = ref([])
const submitting = ref(false)
+const statusText = rowPenaltyStatusText
+const statusType = rowPenaltyStatusType
+
const handleAction = (action) => {
+ isPlatformAction.value = false
currentAction.value = action
actionTitle.value = action === 'agree' ? '同意申诉(处罚将撤销)' : '拒绝申诉'
reason.value = ''
@@ -108,6 +120,16 @@ const handleAction = (action) => {
actionDialog.value = true
}
+const handlePlatformAction = (action) => {
+ isPlatformAction.value = true
+ currentAction.value = action
+ actionTitle.value = action === 'platform_approve' ? '同意平台审核' : '驳回罚款申请'
+ reason.value = ''
+ fileList.value = []
+ selectedFiles.value = []
+ actionDialog.value = true
+}
+
const handleFileChange = (file) => { selectedFiles.value.push(file.raw) }
const handleFileRemove = (file) => {
const idx = selectedFiles.value.indexOf(file.raw)
@@ -117,21 +139,20 @@ const handleFileRemove = (file) => {
const submitAction = async () => {
submitting.value = true
try {
- const formData = new FormData()
- formData.append('username', localStorage.getItem('username') || '')
- formData.append('fadan_id', props.fadan.id)
- formData.append('action', currentAction.value)
- formData.append('chuli_liyou', reason.value)
- selectedFiles.value.forEach(f => formData.append('tupian', f))
-
- // 直接使用 request 发送亦可,这里使用 uploadFiles 并附带字段
- // 因为 uploadFiles 接受额外数据和文件,但需要注意文件字段名是 'tupian'
- const res = await uploadFiles(JITUAN_API.penaltyAction, selectedFiles.value, {
- username: localStorage.getItem('username') || '',
+ const username = localStorage.getItem('username') || ''
+ const payload = {
+ username,
fadan_id: props.fadan.id,
action: currentAction.value,
chuli_liyou: reason.value
- }, 'tupian')
+ }
+
+ let res
+ if (isPlatformAction.value) {
+ res = await request.post(JITUAN_API.penaltyPlatformAudit, payload)
+ } else {
+ res = await uploadFiles(JITUAN_API.penaltyAction, selectedFiles.value, payload, 'tupian')
+ }
if (res.code === 0) {
ElMessage.success('处理成功')
@@ -148,15 +169,6 @@ const submitAction = async () => {
}
}
-const statusText = (code) => ({1:'待缴纳',2:'已缴纳',3:'申诉中',4:'申诉成功'}[code]||'未知')
-const statusType = (code) => {
- if (code === 1) return 'danger'
- if (code === 2) return 'success'
- if (code === 3) return 'warning'
- if (code === 4) return 'info'
- return ''
-}
-
watch(() => props.visible, (val) => { if (!val) actionDialog.value = false })
@@ -166,5 +178,5 @@ watch(() => props.visible, (val) => { if (!val) actionDialog.value = false })
.section-title { font-weight: 600; margin-bottom: 10px; }
.img-grid { display: flex; flex-wrap: wrap; gap: 10px; }
.grid-img { width: 100px; height: 100px; border-radius: 8px; }
-.actions { margin-top: 20px; display: flex; gap: 12px; }
-
\ No newline at end of file
+.actions { margin-top: 20px; display: flex; flex-wrap: wrap; gap: 12px; }
+
diff --git a/src/views/punishment/components/FadanList.vue b/src/views/punishment/components/FadanList.vue
index 5165810..bfd7864 100644
--- a/src/views/punishment/components/FadanList.vue
+++ b/src/views/punishment/components/FadanList.vue
@@ -8,7 +8,7 @@
- {{ statusText(row.zhuangtai) }}
+ {{ rowPenaltyStatusText(row) }}
@@ -35,6 +35,7 @@