fix(admin): add distribution views and correct dist ignore rule

Wire router imports to promoter list and retail config pages. Remove the
overbroad dist* gitignore entry that matched src/views/distribution/.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
msh-agent
2026-05-02 22:49:58 +08:00
parent b00b9b08b3
commit d7c870ced7
3 changed files with 282 additions and 1 deletions

View File

@@ -1,7 +1,6 @@
.DS_Store
node_modules/
dist/
dist*/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@@ -0,0 +1,136 @@
<template>
<div class="divBox">
<el-card v-loading="loading" class="box-card">
<el-form
v-if="formVisible"
ref="formRef"
:model="form"
:rules="rules"
label-width="160px"
size="small"
class="mt20"
>
<el-form-item label="启用分销" prop="brokerageFuncStatus">
<el-radio-group v-model="form.brokerageFuncStatus">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">关闭</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="分销额度(元)" prop="storeBrokerageQuota">
<el-input-number v-model="form.storeBrokerageQuota" :min="-1" :step="1" controls-position="right" />
<span class="ml10 text-muted">-1 关闭0 用户累计消费达该金额自动成为分销员</span>
</el-form-item>
<el-form-item label="一级返佣比例(%)" prop="storeBrokerageRatio">
<el-input-number v-model="form.storeBrokerageRatio" :min="0" :max="100" controls-position="right" />
</el-form-item>
<el-form-item label="二级返佣比例(%)" prop="storeBrokerageTwo">
<el-input-number v-model="form.storeBrokerageTwo" :min="0" :max="100" controls-position="right" />
</el-form-item>
<el-form-item label="分销关系绑定" prop="brokerageBindind">
<el-radio-group v-model="form.brokerageBindind">
<el-radio :label="0">所有用户</el-radio>
<el-radio :label="1">仅新用户</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="提现最低金额" prop="userExtractMinPrice">
<el-input-number v-model="form.userExtractMinPrice" :min="0" :precision="2" :step="1" controls-position="right" />
</el-form-item>
<el-form-item label="提现银行说明" prop="userExtractBank">
<el-input v-model="form.userExtractBank" type="textarea" :rows="4" placeholder="每行一个银行或说明" />
</el-form-item>
<el-form-item label="佣金冻结时间(天)" prop="extractTime">
<el-input-number v-model="form.extractTime" :min="0" :step="1" controls-position="right" />
</el-form-item>
<el-form-item label="分销气泡" prop="storeBrokerageIsBubble">
<el-radio-group v-model="form.storeBrokerageIsBubble">
<el-radio :label="0">展示</el-radio>
<el-radio :label="1">不展示</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button type="primary" v-hasPermi="['admin:retail:spread:manage:set']" @click="submitForm">保存</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import { configApi, configUpdateApi } from '@/api/distribution';
import { Debounce } from '@/utils/validate';
import { checkPermi } from '@/utils/permission';
const defaultForm = () => ({
brokerageFuncStatus: 0,
storeBrokerageQuota: -1,
storeBrokerageRatio: 0,
storeBrokerageTwo: 0,
brokerageBindind: 0,
userExtractMinPrice: 0,
userExtractBank: '',
extractTime: 0,
storeBrokerageIsBubble: 0,
});
export default {
name: 'DistributionConfig',
data() {
return {
loading: false,
formVisible: false,
form: defaultForm(),
rules: {
brokerageFuncStatus: [{ required: true, message: '请选择', trigger: 'change' }],
storeBrokerageQuota: [{ required: true, message: '必填', trigger: 'blur' }],
storeBrokerageRatio: [{ required: true, message: '必填', trigger: 'blur' }],
storeBrokerageTwo: [{ required: true, message: '必填', trigger: 'blur' }],
brokerageBindind: [{ required: true, message: '请选择', trigger: 'change' }],
userExtractMinPrice: [{ required: true, message: '必填', trigger: 'blur' }],
userExtractBank: [{ required: true, message: '必填', trigger: 'blur' }],
extractTime: [{ required: true, message: '必填', trigger: 'blur' }],
storeBrokerageIsBubble: [{ required: true, message: '请选择', trigger: 'change' }],
},
};
},
mounted() {
if (checkPermi(['admin:retail:spread:manage:get'])) {
this.load();
}
},
methods: {
load() {
this.loading = true;
this.formVisible = false;
configApi()
.then((res) => {
this.form = Object.assign(defaultForm(), res || {});
this.formVisible = true;
})
.finally(() => {
this.loading = false;
});
},
submitForm: Debounce(function () {
this.$refs.formRef.validate((valid) => {
if (!valid) return;
const ration = (this.form.storeBrokerageTwo || 0) + (this.form.storeBrokerageRatio || 0);
if (ration > 100) {
this.$message.error('一级与二级返佣比例之和不能超过 100%');
return;
}
configUpdateApi(this.form).then(() => {
this.$message.success('保存成功');
this.load();
});
});
}),
},
};
</script>
<style scoped>
.text-muted {
color: #909399;
font-size: 12px;
}
</style>

View File

@@ -0,0 +1,146 @@
<template>
<div class="divBox">
<el-card class="box-card">
<div slot="header" class="clearfix">
<div class="container">
<el-form inline size="small" @submit.native.prevent>
<el-form-item label="关键字:">
<el-input
v-model="tableFrom.keywords"
placeholder="姓名、电话、UID"
clearable
class="selWidth"
@keyup.enter.native="getList(1)"
/>
</el-form-item>
<el-form-item label="时间:">
<el-select v-model="tableFrom.dateLimit" placeholder="全部" clearable class="selWidth" @change="getList(1)">
<el-option label="今天" value="today" />
<el-option label="昨天" value="yesterday" />
<el-option label="最近7天" value="lately7" />
<el-option label="最近30天" value="lately30" />
<el-option label="本月" value="month" />
<el-option label="本年" value="year" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getList(1)">搜索</el-button>
</el-form-item>
</el-form>
</div>
</div>
<el-table v-loading="listLoading" :data="tableData.data" style="width: 100%" size="mini">
<el-table-column prop="uid" label="UID" min-width="70" />
<el-table-column label="头像" min-width="70">
<template slot-scope="scope">
<el-image
v-if="scope.row.avatar"
style="width: 36px; height: 36px"
:src="scope.row.avatar"
:preview-src-list="[scope.row.avatar]"
/>
<span v-else></span>
</template>
</el-table-column>
<el-table-column prop="nickname" label="昵称" min-width="120">
<template slot-scope="scope">
<span>{{ scope.row.nickname | filterEmpty }}</span>
</template>
</el-table-column>
<el-table-column prop="realName" label="姓名" min-width="100">
<template slot-scope="scope">
<span>{{ scope.row.realName | filterEmpty }}</span>
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" min-width="110">
<template slot-scope="scope">
<span>{{ scope.row.phone | filterEmpty }}</span>
</template>
</el-table-column>
<el-table-column prop="spreadNickname" label="上级" min-width="110">
<template slot-scope="scope">
<span>{{ scope.row.spreadNickname | filterEmpty }}</span>
</template>
</el-table-column>
<el-table-column prop="brokeragePrice" label="未提现佣金" min-width="100" align="right" />
<el-table-column prop="totalBrokeragePrice" label="佣金累计" min-width="100" align="right" />
<el-table-column prop="spreadCount" label="推广人数" min-width="90" align="center" />
<el-table-column prop="spreadOrderNum" label="推广订单数" min-width="100" align="center" />
<el-table-column prop="payCount" label="购买次数" min-width="90" align="center" />
<el-table-column label="成为分销员时间" min-width="160">
<template slot-scope="scope">
<span>{{ scope.row.promoterTime ? parseTime(scope.row.promoterTime) : '—' }}</span>
</template>
</el-table-column>
</el-table>
<div class="block mb20">
<el-pagination
:page-sizes="[10, 20, 30, 40]"
:page-size="tableFrom.limit"
:current-page="tableFrom.page"
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="pageChange"
/>
</div>
</el-card>
</div>
</template>
<script>
import { promoterListApi } from '@/api/distribution';
import { checkPermi } from '@/utils/permission';
export default {
name: 'DistributionIndex',
data() {
return {
listLoading: false,
tableFrom: {
page: 1,
limit: 20,
keywords: '',
dateLimit: '',
},
tableData: {
data: [],
total: 0,
},
};
},
mounted() {
if (checkPermi(['admin:retail:list'])) {
this.getList(1);
} else {
this.listLoading = false;
}
},
methods: {
checkPermi,
getList(num) {
this.listLoading = true;
this.tableFrom.page = num ? num : this.tableFrom.page;
promoterListApi(this.tableFrom)
.then((res) => {
this.tableData.data = res.list || [];
this.tableData.total = res.total != null ? Number(res.total) : 0;
this.listLoading = false;
})
.catch(() => {
this.listLoading = false;
});
},
handleSizeChange(val) {
this.tableFrom.limit = val;
this.getList(1);
},
pageChange(page) {
this.tableFrom.page = page;
this.getList();
},
},
};
</script>
<style scoped></style>