Files
medical-mall/pages/mall/admin/distribution/level/index.uvue
2026-02-13 17:29:50 +08:00

344 lines
11 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="admin-page">
<view class="filter-card">
<view class="filter-row">
<view class="filter-item">
<text class="label">是否显示:</text>
<view class="select-mock"><text>全部</text><text class="arrow">▼</text></view>
</view>
<view class="filter-item">
<text class="label">等级名称:</text>
<input class="filter-input" placeholder="请输入等级名称" />
</view>
<view class="filter-btns">
<button class="btn primary" @click="onSearch">查询</button>
</view>
</view>
</view>
<view class="content-card">
<view class="action-bar">
<button class="btn primary small" @click="openEditModal(null)">添加等级</button>
</view>
<view class="table-container">
<view class="table-header">
<view class="col col-id"><text>ID</text></view>
<view class="col col-img"><text>商品图片</text></view>
<view class="col col-name"><text>名称</text></view>
<view class="col col-level"><text>等级</text></view>
<view class="col col-percent"><text>一级分佣比例</text></view>
<view class="col col-percent"><text>二级分佣比例</text></view>
<view class="col col-stat"><text>任务总数</text></view>
<view class="col col-stat"><text>需完成数量</text></view>
<view class="col col-status"><text>是否显示</text></view>
<view class="col col-ops"><text>操作</text></view>
</view>
<view class="table-body">
<view v-for="item in levelList" :key="item.id" class="table-row">
<view class="col col-id"><text>{{ item.id }}</text></view>
<view class="col col-img">
<image class="table-img" src="/static/logo.png" mode="aspectFill" />
</view>
<view class="col col-name"><text>{{ item.name }}</text></view>
<view class="col col-level"><text>{{ item.level }}</text></view>
<view class="col col-percent"><text>{{ item.percent1 }}%</text></view>
<view class="col col-percent"><text>{{ item.percent2 }}%</text></view>
<view class="col col-stat"><text>{{ item.task_total }}</text></view>
<view class="col col-stat"><text>{{ item.task_finish }}</text></view>
<view class="col col-status">
<switch :checked="item.is_visible" color="#1890ff" scale="0.8" @change="() => onToggleVisible(item)" />
</view>
<view class="col col-ops">
<text class="op-link">等级任务</text>
<text class="op-divider">|</text>
<text class="op-link" @click="openEditModal(item)">编辑</text>
<text class="op-divider">|</text>
<text class="op-link" @click="onDelete(item.id)">删除</text>
</view>
</view>
</view>
</view>
<view class="pagination">
<text class="page-info">共 {{ levelList.length }} 条</text>
</view>
</view>
<view v-if="editPopupVisible" class="popup-mask" @click="closeEditModal">
<view class="popup-card" @click.stop>
<view class="popup-header">
<text class="popup-title">{{ editForm.id == null ? '添加分销等级' : '编辑分销等级' }}</text>
<text class="popup-close" @click="closeEditModal">×</text>
</view>
<view class="popup-body">
<view class="popup-item">
<text class="popup-label">等级名称</text>
<input v-model="editForm.name" class="popup-input" placeholder="如:一级分销员" />
</view>
<view class="popup-item">
<text class="popup-label">等级权重</text>
<input v-model="editForm.level" type="number" class="popup-input" placeholder="如1" />
</view>
<view class="popup-item">
<text class="popup-label">一级分佣比例 (%)</text>
<input v-model="editForm.percent1" type="digit" class="popup-input" placeholder="0 - 100" />
</view>
<view class="popup-item">
<text class="popup-label">二级分佣比例 (%)</text>
<input v-model="editForm.percent2" type="digit" class="popup-input" placeholder="0 - 100" />
</view>
<view class="popup-item">
<text class="popup-label">任务总数</text>
<input v-model="editForm.task_total" type="number" class="popup-input" placeholder="如0" />
</view>
<view class="popup-item">
<text class="popup-label">需完成数量</text>
<input v-model="editForm.task_finish" type="number" class="popup-input" placeholder="如0" />
</view>
<view class="popup-item popup-row">
<text class="popup-label">是否显示</text>
<switch :checked="!!editForm.is_visible" color="#1890ff" scale="0.8" @change="(e) => editForm.is_visible = e.detail.value" />
</view>
</view>
<view class="popup-footer">
<button class="btn" @click="closeEditModal">取消</button>
<button class="btn primary" @click="handleSave">保存</button>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted, reactive } from 'vue'
import { getDistributionLevelList, saveDistributionLevel, deleteDistributionLevel, DistributionLevel } from '@/services/admin/distributionService.uts'
const levelList = ref<DistributionLevel[]>([])
const isLoading = ref(false)
const editPopupVisible = ref(false)
const editForm = reactive<DistributionLevel>({
id: undefined,
name: '',
level: 1,
percent1: 0,
percent2: 0,
task_total: 0,
task_finish: 0,
is_visible: true
})
onMounted(() => {
loadLevels()
})
async function loadLevels() {
isLoading.value = true
try {
const res = await getDistributionLevelList()
levelList.value = res
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
isLoading.value = false
}
}
function onSearch() {
loadLevels()
}
function openEditModal(item: DistributionLevel | null) {
if (item != null) {
Object.assign(editForm, item)
} else {
Object.assign(editForm, {
id: undefined,
name: '',
level: levelList.value.length + 1,
percent1: 0,
percent2: 0,
task_total: 0,
task_finish: 0,
is_visible: true
})
}
editPopupVisible.value = true
}
function closeEditModal() {
editPopupVisible.value = false
}
async function handleSave() {
if (!editForm.name) {
uni.showToast({ title: '请输入等级名称', icon: 'none' })
return
}
isLoading.value = true
try {
const success = await saveDistributionLevel(editForm as DistributionLevel)
if (success) {
uni.showToast({ title: '保存成功', icon: 'success' })
closeEditModal()
loadLevels()
} else {
uni.showToast({ title: '保存失败', icon: 'none' })
}
} catch (e) {
uni.showToast({ title: '保存异常', icon: 'none' })
} finally {
isLoading.value = false
}
}
async function onDelete(id: string | undefined) {
if (id == null) return
uni.showModal({
title: '确认删除',
content: '确定要删除该分销等级吗?',
success: async (res) => {
if (res.confirm) {
isLoading.value = true
try {
const success = await deleteDistributionLevel(id)
if (success) {
uni.showToast({ title: '删除成功' })
loadLevels()
}
} finally {
isLoading.value = false
}
}
}
})
}
async function onToggleVisible(item: DistributionLevel) {
const updated = { ...item, is_visible: !item.is_visible } as DistributionLevel
const success = await saveDistributionLevel(updated)
if (success) {
loadLevels()
}
}
</script>
<style scoped lang="scss">
.admin-page { padding: 0; }
.filter-card { background: #fff; padding: 24px; margin-bottom: 16px; border-radius: 4px; }
.filter-row { display: flex; flex-direction: row; align-items: center; gap: 24px; }
.label { font-size: 14px; color: #333; }
.select-mock { display: flex; flex-direction: row; align-items: center; justify-content: space-between; border: 1px solid #d9d9d9; border-radius: 2px; height: 32px; width: 160px; padding: 0 12px; background: #fff; text { font-size: 14px; color: #666; } .arrow { font-size: 10px; color: #bfbfbf; } }
.filter-input { border: 1px solid #d9d9d9; height: 32px; width: 220px; padding: 0 12px; font-size: 14px; }
.btn { height: 32px; padding: 0 16px; font-size: 14px; border-radius: 2px; border: 1px solid #d9d9d9; background: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.btn.primary { background: #1890ff; border-color: #1890ff; color: #fff; }
.content-card { background: #fff; border-radius: 4px; }
.action-bar { padding: 16px 24px; }
.table-container { padding: 0 24px 24px; }
.table-header { display: flex; flex-direction: row; background: #f8faff; border-bottom: 1px solid #f0f0f0; padding: 12px 0; }
.table-row { display: flex; flex-direction: row; border-bottom: 1px solid #f0f0f0; padding: 12px 0; align-items: center; &:hover { background: #fafafa; } }
.col { padding: 0 8px; display: flex; align-items: center; font-size: 14px; color: #333; }
.col-id { width: 50px; } .col-img { width: 80px; justify-content: center; } .col-name { width: 120px; } .col-level { width: 80px; justify-content: center; } .col-percent { width: 120px; justify-content: center; } .col-stat { width: 100px; justify-content: center; } .col-status { width: 100px; justify-content: center; } .col-ops { flex: 1; justify-content: flex-end; padding-right: 16px; }
.table-img { width: 32px; height: 32px; border-radius: 2px; }
.op-link { color: #1890ff; cursor: pointer; }
.op-divider { color: #e8e8e8; margin: 0 8px; }
.pagination { padding: 16px 24px; border-top: 1px solid #f0f0f0; }
.page-info { font-size: 14px; color: #999; }
/* 弹窗样式 */
.popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.popup-card {
width: 500px;
background-color: #fff;
border-radius: 8px;
display: flex;
flex-direction: column;
overflow: hidden;
}
.popup-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
}
.popup-title {
font-size: 16px;
font-weight: bold;
color: #333;
}
.popup-close {
font-size: 20px;
color: #999;
cursor: pointer;
padding: 4px;
}
.popup-body {
padding: 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
.popup-item {
display: flex;
flex-direction: column;
gap: 8px;
}
.popup-row {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.popup-label {
font-size: 14px;
color: #666;
}
.popup-input {
border: 1px solid #d9d9d9;
border-radius: 4px;
height: 36px;
padding: 0 12px;
font-size: 14px;
width: 100%;
}
.popup-footer {
padding: 16px 24px;
border-top: 1px solid #f0f0f0;
display: flex;
flex-direction: row;
justify-content: flex-end;
gap: 12px;
}
.btn.ghost {
background-color: #fff;
color: #666;
border: 1px solid #d9d9d9;
}
</style>