This commit is contained in:
qsh
2026-02-03 20:21:06 +08:00
parent ec95ab4933
commit d97a222637
20 changed files with 1049 additions and 3186 deletions

View File

@@ -0,0 +1,54 @@
import request from '@/utils/request';
// 查询分页
export const getDistributorPage = params => {
return request({
url: '/applet/xunjia/distributor/page',
method: 'get',
params
});
};
// 新增
export const addDistributor = data => {
return request({
url: '/applet/xunjia/distributor/create',
method: 'post',
data
});
};
// 修改
export const updateDistributor = data => {
return request({
url: '/applet/xunjia/distributor/update',
method: 'put',
data
});
};
// 删除
export const deleteDistributor = id => {
return request({
url: '/applet/xunjia/distributor/delete',
method: 'delete',
params: { id }
});
};
// 修改状态
export const updateDistributorStatus = data => {
return request({
url: '/applet/xunjia/distributor/tatus/update',
method: 'put',
data
});
};
// 获取详情
export const getDistributorDetail = id => {
return request({
url: '/applet/xunjia/distributor/get/' + id,
method: 'get'
});
};

View File

@@ -0,0 +1,9 @@
import request from '@/utils/request';
export const getRulesInfo = params => {
return request({
url: '/applet/xunjia/tenant/get',
method: 'get',
params
});
};

View File

@@ -30,48 +30,6 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/avatar/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/info/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/info/edit",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/pwd/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/setting/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/help/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/about/index",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/common/webview/index",
"style": {
@@ -102,12 +60,6 @@
"navigationStyle": "custom"
}
},
{
"path": "pages/distributor/rule",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/distribution/data",
"style": {

View File

@@ -16,35 +16,48 @@
<view class="section-title">规则说明</view>
<view class="info-card">
<view class="info-item"> 分润规则适用于所有分销员</view>
<view class="info-item"> 扫码注册分润学员通过推广码扫码注册后分销员可获得的分润</view>
<view class="info-item"> 购买会员分润学员通过推广码购买会员后分销员可获得的分润</view>
<view class="info-item"> 分润比例按会员价格的百分比计算最高不超过50%</view>
<view class="info-item"> 注册分润学员通过推广码扫码注册后分销员可获得的分润</view>
<view class="info-item"> 消费分润学员通过推广码购买会员后分销员可获得的分润</view>
<view class="info-item"> 分润比例按会员价格的百分比计算</view>
</view>
</view>
<!-- 分润规则配置 -->
<view class="rule-config-section">
<view class="section-title">分润规则配置</view>
<view class="rule-hint">
<view class="info-item"> 固定金额直接设置具体金额</view>
<view class="info-item"> 比例分润按预设基准金额的百分比计算</view>
</view>
<view class="rule-card">
<!-- 扫码注册分润 -->
<view class="rule-item">
<!-- 注册分润 -->
<view class="rule-item" v-for="(rule, idx) in profitRules" :key="rule.id || idx">
<view class="rule-header">
<view class="rule-title">扫码注册分润</view>
<view class="rule-title">
{{ rule.type === 'register' ? '注册分润' : '消费分润' }}
<view v-if="rule.type === 'consume'" class="rule-actions">
<view class="delete-btn" @click="deleteConsumeRule(idx)">
<text style="color: #f56c6c; font-size: 24rpx;">删除</text>
</view>
</view>
</view>
<view class="rule-toggle">
<switch
:checked="scanRegisterRule.enabled"
@change="onScanRegisterToggle"
class="toggle-switch"
active-color="#409eff"
/>
<view class="rule-control">
<radio-group @change="e => onProfitTypeChange(idx, e.detail.value)">
<label v-for="(option, index) in profitTypeOptions" :key="index" class="radio-item">
<radio :value="option.value" :checked="rule.profitType === option.value" />
<text class="radio-label">{{ option.label }}</text>
</label>
</radio-group>
</view>
</view>
<view v-if="scanRegisterRule.enabled" class="rule-content">
<view class="rule-row">
</view>
<view class="rule-content">
<view class="rule-row" v-if="rule.profitType == '1'">
<view class="rule-label">分润金额</view>
<view class="rule-control">
<input
v-model="scanRegisterRule.amount"
v-model="rule.amount"
type="number"
class="rule-input"
placeholder="请输入分润金额"
@@ -55,32 +68,11 @@
<view class="rule-unit"></view>
</view>
</view>
<view class="rule-hint">
固定金额分润学员扫码注册后立即发放
建议设置为5-20
</view>
</view>
</view>
<!-- 购买会员分润 -->
<view class="rule-item">
<view class="rule-header">
<view class="rule-title">购买会员分润</view>
<view class="rule-toggle">
<switch
:checked="memberPurchaseRule.enabled"
@change="onMemberPurchaseToggle"
class="toggle-switch"
active-color="#409eff"
/>
</view>
</view>
<view v-if="memberPurchaseRule.enabled" class="rule-content">
<view class="rule-row">
<view class="rule-row" v-else-if="rule.profitType == '2'">
<view class="rule-label">分润比例</view>
<view class="rule-control">
<input
v-model="memberPurchaseRule.percentage"
v-model="rule.percentage"
type="number"
class="rule-input"
placeholder="请输入分润比例"
@@ -91,144 +83,75 @@
<view class="rule-unit">%</view>
</view>
</view>
<view class="rule-row">
<view class="rule-label">会员类型</view>
<!-- 消费分润VIP选择 -->
<view v-if="rule.type === 'consume'">
<view class="rule-label" style="margin-bottom: 10rpx;">选择会员类型</view>
<view class="rule-control">
<picker
:range="memberTypes"
:value="memberTypeIndex"
@change="onMemberTypeChange"
class="picker"
>
<view class="picker-text">{{ memberTypes[memberTypeIndex] }}</view>
</picker>
<view class="vip-list">
<label v-for="vip in vipList" :key="vip.memberId" class="vip-item checkbox-item"
@click="onVipChange(idx, vip.memberId)">
<checkbox
:value="vip.memberId"
:checked="rule.selectedVips.includes(vip.memberId)"
:disabled="isVipSelectedInOtherRules(idx, vip.memberId)"
/>
<view class="checkbox-label" :class="{ 'disabled': isVipSelectedInOtherRules(idx, vip.memberId) }">
<text>{{ vip.carName || '' }}</text>
<text>{{ vip.memberName || '' }}</text>
<text>{{ vip.discount ? ' ' + vip.discount : '' }}</text>
</view>
</view>
<view class="rule-hint">
按会员价格的百分比计算分润
最高分润比例为50%
建议设置为10%-30%
</label>
</view>
</view>
</view>
</view>
</view>
<!-- 会员价格设置 -->
<view class="price-section">
<view class="section-title">会员价格设置</view>
<view class="price-card">
<view class="price-item">
<view class="price-label">月度会员价格</view>
<view class="price-control">
<input
v-model="memberPrices.monthly"
type="number"
class="price-input"
placeholder="请输入月度会员价格"
min="0"
max="1000"
step="0.1"
/>
<view class="price-unit"></view>
</view>
</view>
<view class="price-item">
<view class="price-label">季度会员价格</view>
<view class="price-control">
<input
v-model="memberPrices.quarterly"
type="number"
class="price-input"
placeholder="请输入季度会员价格"
min="0"
max="3000"
step="0.1"
/>
<view class="price-unit"></view>
</view>
</view>
<view class="price-item">
<view class="price-label">年度会员价格</view>
<view class="price-control">
<input
v-model="memberPrices.yearly"
type="number"
class="price-input"
placeholder="请输入年度会员价格"
min="0"
max="10000"
step="0.1"
/>
<view class="price-unit"></view>
</view>
<!-- 新增消费分润规则按钮 -->
<view class="add-rule-btn" @click="addConsumeRule">
<text style="color: #409eff; font-size: 28rpx;">+ 新增消费分润规则</text>
</view>
</view>
</view>
<!-- 分润预览 -->
<view class="preview-section">
<view class="section-title">分润预览</view>
<view class="preview-card">
<view class="preview-item">
<view class="preview-label">月度会员分润</view>
<view class="preview-value">{{ calculatePreview('monthly') }}</view>
</view>
<view class="preview-item">
<view class="preview-label">季度会员分润</view>
<view class="preview-value">{{ calculatePreview('quarterly') }}</view>
</view>
<view class="preview-item">
<view class="preview-label">年度会员分润</view>
<view class="preview-value">{{ calculatePreview('yearly') }}</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
import { ref, onMounted } from "vue"
import { getVipTypeList } from "@/api/member"
// 扫码注册分润规则
const scanRegisterRule = ref({
enabled: true,
amount: 10
})
// 购买会员分润规则
const memberPurchaseRule = ref({
enabled: true,
percentage: 20
})
// 会员类型选项
const memberTypes = ['全部会员类型', '月度会员', '季度会员', '年度会员']
const memberTypeIndex = ref(0)
// 会员价格
const memberPrices = ref({
monthly: 39.9,
quarterly: 99.9,
yearly: 299.9
})
// 计算分润预览
function calculatePreview(type) {
if (!memberPurchaseRule.value.enabled) {
return '¥0.00'
// 分润规则数组
const profitRules = ref([
{
type: 'register', // 注册分润
profitType: '1', // 固定金额
amount: 10,
percentage: 0
},
{
id: Date.now(), // 唯一标识
type: 'consume', // 消费分润
profitType: '2', // 比例分润
amount: 0,
percentage: 20,
selectedVips: [] // 选中的VIP
}
])
const price = memberPrices.value[type]
const percentage = memberPurchaseRule.value.percentage
const amount = (price * percentage) / 100
const vipList = ref([])
return `¥${amount.toFixed(2)}`
}
// 分润方式选项
const profitTypeOptions = [{ label: '固定金额', value: '1' }, { label: '比例分润', value: '2' }]
onMounted(() => {
// 实际项目中应从接口获取分润规则配置
// loadProfitRules()
getVipTypeList().then(res => {
vipList.value = res.data?.list?.filter(item => item.useTypes.includes(1)) || []
})
})
// 返回上一页
@@ -259,19 +182,71 @@
})
}
// 扫码注册分润开关
function onScanRegisterToggle(e) {
scanRegisterRule.value.enabled = e.detail.value
// 分润方式变更
function onProfitTypeChange(idx, profitType) {
const rule = profitRules.value[idx]
if (rule) {
rule.profitType = profitType
// 重置对应的值
if (profitType === '1') {
rule.percentage = 0
} else if (profitType === '2') {
rule.amount = 0
}
}
}
// 购买会员分润开关
function onMemberPurchaseToggle(e) {
memberPurchaseRule.value.enabled = e.detail.value
// 新增消费分润规则
function addConsumeRule() {
profitRules.value.push({
id: Date.now(), // 唯一标识
type: 'consume', // 消费分润
profitType: '2', // 比例分润
amount: 0,
percentage: 20,
selectedVips: [] // 选中的VIP
})
}
// 会员类型变更
function onMemberTypeChange(e) {
memberTypeIndex.value = e.detail.value
// 删除消费分润规则
function deleteConsumeRule(idx) {
if (profitRules.value[idx].type === 'consume') {
profitRules.value.splice(idx, 1)
}
}
// 检查会员类型是否在其他消费分润规则中被选中
function isVipSelectedInOtherRules(currentIdx, vipId) {
return profitRules.value.some((otherRule, otherIdx) => {
return otherIdx !== currentIdx &&
otherRule.type === 'consume' &&
otherRule.selectedVips.includes(vipId)
})
}
// VIP选择变更确保会员类型不重复
function onVipChange(idx, vipId) {
if (profitRules.value[idx]) {
const vipIndex = profitRules.value[idx].selectedVips.indexOf(vipId)
if (vipIndex > -1) {
// 取消选择
profitRules.value[idx].selectedVips.splice(vipIndex, 1)
console.log('取消选择',idx+1, profitRules.value[idx].selectedVips.length)
} else {
// 检查是否在其他消费分润规则中已选中
const isDuplicate = isVipSelectedInOtherRules(idx, vipId)
if (!isDuplicate) {
profitRules.value[idx].selectedVips.push(vipId)
} else {
uni.showToast({
title: '该会员类型已在其他规则中选中',
icon: 'none',
duration: 2000
})
}
}
}
}
</script>
@@ -306,6 +281,7 @@
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
margin-bottom: 16rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
@@ -317,6 +293,11 @@
font-size: 40rpx;
color: #303133;
cursor: pointer;
transition: color 0.3s ease;
}
.back-icon:hover {
color: #409eff;
}
.header-title {
@@ -335,18 +316,29 @@
color: #409eff;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
padding: 8rpx 16rpx;
border-radius: 8rpx;
}
.save-btn:hover {
background-color: rgba(64, 158, 255, 0.1);
}
/* 通用部分样式 */
.rule-info-section,
.rule-config-section,
.price-section,
.preview-section {
.rule-config-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
transition: box-shadow 0.3s ease;
}
.rule-info-section:hover,
.rule-config-section:hover {
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.12);
}
.section-title {
@@ -364,6 +356,7 @@
background-color: #f9f9f9;
border-radius: 12rpx;
padding: 24rpx;
border: 1rpx solid #e4e7ed;
}
.info-item {
@@ -384,6 +377,13 @@
background-color: #f9f9f9;
border-radius: 12rpx;
padding: 24rpx;
border: 1rpx solid #e4e7ed;
transition: all 0.3s ease;
}
.rule-item:hover {
background-color: #f0f2f5;
border-color: #dcdfe6;
}
.rule-header {
@@ -399,6 +399,41 @@
color: #303133;
}
.rule-actions {
display: flex;
align-items: center;
gap: 16rpx;
}
.delete-btn {
margin-top: 8rpx;
padding: 8rpx 16rpx;
border-radius: 8rpx;
background-color: rgba(245, 108, 108, 0.1);
cursor: pointer;
transition: all 0.3s ease;
}
.delete-btn:hover {
background-color: rgba(245, 108, 108, 0.2);
}
.add-rule-btn {
margin-top: 24rpx;
padding: 20rpx;
background-color: #ecf5ff;
border: 1rpx dashed #409eff;
border-radius: 12rpx;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.add-rule-btn:hover {
background-color: #ebefff;
border-color: #66b1ff;
}
.rule-content {
display: flex;
flex-direction: column;
@@ -419,7 +454,25 @@
.rule-control {
display: flex;
align-items: center;
gap: 8rpx;
gap: 24rpx;
}
.radio-item {
display: flex;
align-items: center;
cursor: pointer;
transition: color 0.3s ease;
margin-bottom: 8rpx;
}
.radio-item:hover .radio-label {
color: #409eff;
}
.radio-label {
margin-left: 8rpx;
font-size: 24rpx;
color: #303133;
}
.rule-input {
@@ -431,6 +484,13 @@
padding: 0 16rpx;
text-align: center;
font-size: 24rpx;
transition: all 0.3s ease;
}
.rule-input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
.rule-unit {
@@ -445,89 +505,59 @@
line-height: 1.4;
}
.picker {
/* VIP列表样式 */
.vip-list {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.vip-item {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
min-width: 200rpx;
padding: 12rpx 16rpx;
cursor: pointer;
transition: all 0.3s ease;
}
.picker-text {
font-size: 24rpx;
.vip-item:hover {
border-color: #409eff;
box-shadow: 0 2rpx 8rpx rgba(64, 158, 255, 0.1);
}
.vip-label {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 15rpx;
font-size: 20rpx;
color: #303133;
white-space: nowrap;
}
/* 会员价格设置 */
.price-card {
display: flex;
flex-direction: column;
gap: 16rpx;
/* 禁用状态样式 */
.checkbox-label.disabled {
color: #c0c4cc !important;
opacity: 0.5 !important;
}
.price-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
/* 禁用的checkbox样式 */
checkbox[disabled] {
opacity: 0.5 !important;
}
.price-label {
font-size: 24rpx;
color: #606266;
checkbox[disabled] .uni-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #f5f7fa !important;
}
.price-control {
display: flex;
align-items: center;
gap: 8rpx;
}
.price-input {
width: 160rpx;
height: 60rpx;
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 0 16rpx;
text-align: center;
font-size: 24rpx;
}
.price-unit {
font-size: 24rpx;
color: #606266;
}
/* 分润预览 */
.preview-card {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.preview-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx;
background-color: #f9f9f9;
border-radius: 12rpx;
}
.preview-label {
font-size: 24rpx;
color: #606266;
}
.preview-value {
font-size: 28rpx;
font-weight: bold;
color: #f56c6c;
checkbox[disabled] .uni-checkbox-input.uni-checkbox-input-checked {
border-color: #dcdfe6 !important;
background-color: #dcdfe6 !important;
}
</style>

View File

@@ -41,26 +41,16 @@
<view class="form-row">
<view class="form-label">状态</view>
<view class="form-control">
<picker
:range="statusOptions"
:value="statusIndex"
@change="onStatusChange"
class="picker"
<radio-group @change="onStatusChange">
<label
v-for="(option, index) in statusOptions"
:key="index"
class="radio-item"
>
<view class="picker-text">{{ statusOptions[statusIndex] }}</view>
</picker>
</view>
</view>
<view class="form-row">
<view class="form-label">备注</view>
<view class="form-control">
<textarea
v-model="distributorForm.remark"
class="form-textarea"
placeholder="请输入备注信息"
maxlength="200"
></textarea>
<view class="textarea-count">{{ distributorForm.remark.length }}/200</view>
<radio :value="index.toString()" :checked="distributorForm.status == index.toString()" />
<text class="radio-label">{{ option }}</text>
</label>
</radio-group>
</view>
</view>
</view>
@@ -70,22 +60,20 @@
<script setup>
import { ref, onMounted } from "vue"
import {
addDistributor,
} from "@/api/distribution/distributor";
// 分销员表单数据
const distributorForm = ref({
name: '',
phone: '',
status: '启用',
remark: ''
status: '0',
})
// 状态选项
const statusOptions = ['启用', '禁用']
const statusIndex = ref(0)
onMounted(() => {
// 初始化表单数据
})
// 返回上一页
function goBack() {
@@ -112,29 +100,30 @@
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
addDistributor(distributorForm.value).then(res => {
uni.hideLoading()
uni.showToast({
title: '添加成功',
icon: 'success'
})
// 实际项目中应调用接口保存分销员
// saveDistributorData()
// 保存成功后返回上一页
setTimeout(() => {
goBack()
}, 1000)
}, 1500)
}).catch(err => {
uni.hideLoading()
uni.showToast({
title: err.message || '添加失败',
icon: 'none'
})
})
}
// 状态变更
function onStatusChange(e) {
const value = e.detail.value
statusIndex.value = value
distributorForm.value.status = statusOptions[value]
distributorForm.value.status = e.detail.value.toString()
}
</script>
@@ -328,67 +317,23 @@
color: #909399;
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.distributor-add-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
/* Radio样式 */
radio-group {
display: flex;
gap: 32rpx;
}
.form-section {
margin: 0 32rpx 24rpx;
padding: 40rpx;
.radio-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 32rpx;
}
.form-card {
padding: 32rpx;
}
.form-row {
margin-bottom: 32rpx;
}
.form-label {
font-size: 26rpx;
}
.form-input,
.picker {
padding: 24rpx 28rpx;
font-size: 26rpx;
border-radius: 14rpx;
}
.picker-text {
font-size: 26rpx;
}
.form-textarea {
height: 200rpx;
padding: 24rpx 28rpx;
font-size: 26rpx;
border-radius: 14rpx;
}
.form-input::placeholder,
.form-textarea::placeholder {
.radio-label {
font-size: 24rpx;
color: #303133;
}
.textarea-count {
font-size: 20rpx;
}
.save-btn {
font-size: 28rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {

View File

@@ -1,11 +1,11 @@
<template>
<view class="distributor-edit-container">
<view class="distributor-add-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">编辑分销员</view>
<view class="header-title">添加分销员</view>
<view class="header-right" @click="saveDistributor">
<view class="save-btn">保存</view>
</view>
@@ -41,61 +41,64 @@
<view class="form-row">
<view class="form-label">状态</view>
<view class="form-control">
<picker
:range="statusOptions"
:value="statusIndex"
@change="onStatusChange"
class="picker"
<radio-group @change="onStatusChange">
<label
v-for="(option, index) in statusOptions"
:key="index"
class="radio-item"
>
<view class="picker-text">{{ statusOptions[statusIndex] }}</view>
</picker>
<radio :value="index.toString()" :checked="distributorForm.status == index.toString()" />
<text class="radio-label">{{ option }}</text>
</label>
</radio-group>
</view>
</view>
<view class="form-row">
<view class="form-label">备注</view>
<view class="form-control">
<textarea
v-model="distributorForm.remark"
class="form-textarea"
placeholder="请输入备注信息"
maxlength="200"
></textarea>
<view class="textarea-count">{{ distributorForm.remark.length }}/200</view>
</view>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="action-section">
<view class="action-btn delete-btn" @click="deleteDistributor">
删除分销员
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from "vue"
import { ref } from "vue"
import { onLoad } from "@dcloudio/uni-app";
import {
updateDistributor,
getDistributorDetail
} from "@/api/distribution/distributor";
// 分销员表单数据
const distributorForm = ref({
id: '',
name: '张三',
phone: '13800138001',
status: '启用',
remark: '默认分销员'
name: '',
phone: '',
status: '0',
remark: ''
})
// 状态选项
const statusOptions = ['启用', '禁用']
const statusIndex = ref(0)
onMounted(() => {
// 实际项目中应从接口获取分销员详情
// loadDistributorDetail()
onLoad((options) => {
// 获取分销员信息
getDistributorInfo(options.id)
})
// 获取分销员信息
function getDistributorInfo(id) {
getDistributorDetail(id).then(res => {
distributorForm.value = {
...res.data,
status: res.data.status.toString()
}
}).catch(err => {
uni.showToast({
title: err.message || '获取失败',
icon: 'none'
})
})
}
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
@@ -121,47 +124,22 @@
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
updateDistributor(distributorForm.value).then(res => {
uni.hideLoading()
uni.showToast({
title: '保存成功',
icon: 'success'
})
// 实际项目中应调用接口保存分销员
// updateDistributorData()
// 保存成功后返回上一页
setTimeout(() => {
goBack()
}, 1000)
}, 1500)
}
// 删除分销员
function deleteDistributor() {
uni.showModal({
title: '删除分销员',
content: '确定要删除该分销员吗?',
success: function(res) {
if (res.confirm) {
uni.showLoading({ title: '删除中...' })
setTimeout(() => {
}).catch(err => {
uni.hideLoading()
uni.showToast({
title: '删除成功',
icon: 'success'
title: err.message || '添加失败',
icon: 'none'
})
// 实际项目中应调用接口删除分销员
// deleteDistributorData()
// 删除成功后返回上一页
setTimeout(() => {
goBack()
}, 1000)
}, 1500)
}
}
})
}
@@ -169,9 +147,7 @@
// 状态变更
function onStatusChange(e) {
const value = e.detail.value
statusIndex.value = value
distributorForm.value.status = statusOptions[value]
distributorForm.value.status = e.detail.value.toString()
}
</script>
@@ -192,7 +168,7 @@
}
/* #endif */
.distributor-edit-container {
.distributor-add-container {
flex: 1;
display: flex;
flex-direction: column;
@@ -241,7 +217,7 @@
.form-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
@@ -284,22 +260,47 @@
.form-input {
width: 100%;
height: 70rpx;
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
border-radius: 12rpx;
padding: 20rpx 24rpx;
font-size: 24rpx;
color: #303133;
transition: all 0.3s ease;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.02);
}
.form-input:focus {
border-color: #409eff;
box-shadow: 0 0 0 4rpx rgba(64, 158, 255, 0.1);
outline: none;
}
.form-input::placeholder {
color: #909399;
font-size: 22rpx;
}
.picker {
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
border-radius: 12rpx;
padding: 20rpx 24rpx;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.3s ease;
cursor: pointer;
}
.picker:hover {
border-color: #c6e2ff;
box-shadow: 0 2rpx 8rpx rgba(64, 158, 255, 0.1);
}
.picker:active {
background-color: #f5faff;
}
.picker-text {
@@ -312,11 +313,24 @@
height: 160rpx;
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
border-radius: 12rpx;
padding: 20rpx 24rpx;
font-size: 24rpx;
color: #303133;
resize: none;
transition: all 0.3s ease;
box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.02);
}
.form-textarea:focus {
border-color: #409eff;
box-shadow: 0 0 0 4rpx rgba(64, 158, 255, 0.1);
outline: none;
}
.form-textarea::placeholder {
color: #909399;
font-size: 22rpx;
}
.textarea-count {
@@ -327,94 +341,27 @@
color: #909399;
}
/* 操作按钮 */
.action-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
/* Radio样式 */
radio-group {
display: flex;
gap: 32rpx;
}
.action-btn {
width: 100%;
text-align: center;
padding: 20rpx;
border-radius: 8rpx;
.radio-item {
display: flex;
align-items: center;
gap: 8rpx;
}
.radio-label {
font-size: 24rpx;
font-weight: 600;
cursor: pointer;
color: #303133;
}
.delete-btn {
background-color: #fef0f0;
color: #f56c6c;
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.distributor-edit-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.form-section,
.action-section {
margin: 0 32rpx 24rpx;
padding: 40rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 32rpx;
}
.form-card {
padding: 32rpx;
}
.form-row {
margin-bottom: 32rpx;
}
.form-label {
font-size: 26rpx;
}
.form-input,
.picker {
padding: 20rpx;
font-size: 26rpx;
}
.picker-text {
font-size: 26rpx;
}
.form-textarea {
height: 200rpx;
padding: 20rpx;
font-size: 26rpx;
}
.textarea-count {
font-size: 20rpx;
}
.save-btn {
font-size: 28rpx;
}
.action-btn {
font-size: 26rpx;
padding: 24rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.distributor-edit-container {
.distributor-add-container {
max-width: 1000px;
}
@@ -428,7 +375,9 @@
.form-input,
.picker {
padding: 28rpx 32rpx;
font-size: 28rpx;
border-radius: 16rpx;
}
.picker-text {
@@ -436,11 +385,14 @@
}
.form-textarea {
padding: 28rpx 32rpx;
font-size: 28rpx;
border-radius: 16rpx;
}
.action-btn {
font-size: 28rpx;
.form-input::placeholder,
.form-textarea::placeholder {
font-size: 26rpx;
}
}
</style>

View File

@@ -15,25 +15,23 @@
<view class="filter-section">
<view class="filter-row">
<view class="filter-item">
<view class="filter-label">状态</view>
<view class="filter-label">姓名</view>
<view class="filter-control">
<picker
:range="statusOptions"
:value="statusIndex"
@change="onStatusChange"
class="picker"
>
<view class="picker-text">{{ statusOptions[statusIndex] }}</view>
</picker>
<input
v-model="searchName"
class="search-input"
placeholder="请输入姓名"
@input="onSearch"
/>
</view>
</view>
<view class="filter-item">
<view class="filter-label">搜索</view>
<view class="filter-label">手机号</view>
<view class="filter-control">
<input
v-model="searchKeyword"
v-model="searchPhone"
class="search-input"
placeholder="请输入姓名或手机号"
placeholder="请输入手机号"
@input="onSearch"
/>
</view>
@@ -57,17 +55,24 @@
<view class="distributor-name">{{ distributor.name }}</view>
<view class="distributor-meta">
<view class="meta-item">{{ distributor.phone }}</view>
<view class="meta-item status-{{ distributor.statusClass }}">{{ distributor.status }}</view>
<view class="meta-item" :class="{'status-active': distributor.status == 0, 'status-inactive': distributor.status == 1}">{{ statusOptions[distributor.status] }}</view>
</view>
</view>
<view class="distributor-actions">
<view class="action-row">
<view class="action-btn edit-btn" @click="editDistributor(distributor.id)">
编辑
</view>
<view class="action-btn delete-btn" @click="deleteDistributor(distributor.id)">
<view class="action-btn delete-btn" @click="confirmDelete(distributor.id)">
删除
</view>
</view>
<view class="action-row">
<view class="action-btn rule-btn" @click="viewDistributorRules(distributor.id)">
分销规则
</view>
</view>
</view>
</view>
</view>
</view>
@@ -104,37 +109,19 @@
</template>
<script setup>
import { ref, computed, onMounted } from "vue"
import { ref, computed } from "vue"
import { getDistributorPage, deleteDistributor } from '@/api/distribution/distributor'
import { onShow } from "@dcloudio/uni-app"
// 筛选条件
const statusOptions = ['全部状态', '启用', '禁用']
const statusIndex = ref(0)
const searchKeyword = ref('')
const searchName = ref('')
const searchPhone = ref('')
// 分销员列表数据
const distributorList = ref([
{
id: 1,
name: '张三',
phone: '13800138001',
status: '启用',
statusClass: 'active'
},
{
id: 2,
name: '李四',
phone: '13800138002',
status: '启用',
statusClass: 'active'
},
{
id: 3,
name: '王五',
phone: '13800138003',
status: '禁用',
statusClass: 'inactive'
}
])
const distributorList = ref([])
// 状态选项
const statusOptions = ['启用', '禁用']
// 分页信息
const currentPage = ref(1)
@@ -146,9 +133,9 @@
return Math.ceil(totalDistributors.value / pageSize.value)
})
onMounted(() => {
onShow(() => {
// 实际项目中应从接口获取分销员列表
// loadDistributorList()
loadDistributorList()
})
// 返回上一页
@@ -156,6 +143,21 @@
uni.navigateBack({ delta: 1 })
}
const loadDistributorList = async () => {
const params = {
page: currentPage.value,
pageSize: pageSize.value,
name: searchName.value,
phone: searchPhone.value
}
const res = await getDistributorPage(params)
if (res.code == '0000') {
distributorList.value = res.data.list
totalDistributors.value = res.data.total
}
}
// 添加分销员
function addDistributor() {
// 跳转至添加分销员页面
@@ -172,39 +174,35 @@
})
}
// 查看分销规则
function viewDistributorRules(id) {
// 跳转至分销规则页面
uni.navigateTo({
url: '/pages/distribution/profit-rule?id=' + id
})
}
// 删除分销员
function deleteDistributor(id) {
function confirmDelete(id) {
uni.showModal({
title: '删除分销员',
content: '确定要删除该分销员吗?',
success: function(res) {
if (res.confirm) {
// 实际项目中应调用接口删除分销员
const index = distributorList.value.findIndex(item => item.id === id)
if (index !== -1) {
distributorList.value.splice(index, 1)
}
deleteDistributor(id).then(() => {
uni.showToast({
title: '删除成功',
icon: 'success'
title: '删除成功'
})
loadDistributorList()
})
}
}
})
}
// 状态变更
function onStatusChange(e) {
const value = e.detail.value
statusIndex.value = value
// 实际项目中应根据状态筛选分销员
// filterDistributorList()
}
// 搜索
function onSearch() {
// 实际项目中应根据关键词搜索分销员
// searchDistributorList()
loadDistributorList()
}
// 跳转到指定页码
@@ -214,7 +212,7 @@
}
currentPage.value = page
// 实际项目中应加载指定页码的分销员
// loadDistributorPage(page)
loadDistributorList()
}
// 获取姓名首字母
@@ -316,17 +314,6 @@
padding: 16rpx;
}
.picker {
display: flex;
justify-content: space-between;
align-items: center;
}
.picker-text {
font-size: 24rpx;
color: #303133;
}
.search-input {
font-size: 24rpx;
color: #303133;
@@ -397,6 +384,7 @@
display: flex;
gap: 16rpx;
flex-wrap: wrap;
align-items: center;
}
.meta-item {
@@ -413,16 +401,25 @@
}
.distributor-actions {
display: flex;
flex-direction: column;
gap: 12rpx;
align-items: flex-end;
}
.action-row {
display: flex;
gap: 16rpx;
align-items: center;
}
.action-btn {
padding: 8rpx 16rpx;
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 16rpx;
font-size: 24rpx;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
}
.edit-btn {
@@ -430,6 +427,11 @@
color: #409eff;
}
.rule-btn {
background-color: #f0f9eb;
color: #67c23a;
}
.delete-btn {
background-color: #fef0f0;
color: #f56c6c;
@@ -490,91 +492,6 @@
cursor: not-allowed;
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.distributor-list-container {
max-width: 1000px;
margin: 0 auto;
width: 100%;
}
.filter-section {
margin: 0 32rpx 24rpx;
padding: 32rpx;
}
.distributor-list-section {
padding: 0 32rpx;
}
.pagination {
margin: 0 32rpx 32rpx;
padding: 32rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 32rpx;
}
.filter-label {
font-size: 26rpx;
}
.picker-text,
.search-input {
font-size: 26rpx;
}
.filter-control {
padding: 20rpx;
}
.distributor-item {
padding: 32rpx;
}
.distributor-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
margin-right: 32rpx;
}
.avatar-placeholder {
font-size: 36rpx;
}
.distributor-name {
font-size: 32rpx;
}
.distributor-meta {
gap: 24rpx;
}
.meta-item {
font-size: 22rpx;
}
.action-btn {
font-size: 18rpx;
padding: 12rpx 24rpx;
}
.page-info {
font-size: 22rpx;
}
.page-btn {
font-size: 22rpx;
padding: 12rpx 24rpx;
}
.add-btn {
font-size: 28rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {

View File

@@ -1,596 +0,0 @@
<template>
<view class="distributor-rule-container">
<!-- 页面标题 -->
<view class="page-header">
<view class="header-left" @click="goBack">
<view class="back-icon"></view>
</view>
<view class="header-title">分销规则配置</view>
<view class="header-right" @click="saveRule">
<view class="save-btn">保存</view>
</view>
</view>
<!-- 规则配置 -->
<view class="rule-section">
<view class="section-title">基本规则</view>
<view class="rule-card">
<view class="rule-row">
<view class="rule-label">分销员申请审核</view>
<view class="rule-control">
<switch
:checked="ruleForm.needAudit"
@change="onAuditChange"
class="switch"
/>
</view>
</view>
<view class="rule-row">
<view class="rule-label">分销员等级制度</view>
<view class="rule-control">
<switch
:checked="ruleForm.enableLevel"
@change="onLevelChange"
class="switch"
/>
</view>
</view>
<view class="rule-row">
<view class="rule-label">分销员自购优惠</view>
<view class="rule-control">
<switch
:checked="ruleForm.enableSelfBuy"
@change="onSelfBuyChange"
class="switch"
/>
</view>
</view>
<view class="rule-row">
<view class="rule-label">分销员邀请奖励</view>
<view class="rule-control">
<switch
:checked="ruleForm.enableInviteReward"
@change="onInviteRewardChange"
class="switch"
/>
</view>
</view>
</view>
</view>
<!-- 等级配置 -->
<view class="rule-section" v-if="ruleForm.enableLevel">
<view class="section-title">等级配置</view>
<view class="rule-card">
<view class="level-config">
<view
v-for="(level, index) in levelList"
:key="index"
class="level-item"
>
<view class="level-header">
<view class="level-title">{{ level.name }}</view>
<view class="level-condition">
<view class="condition-label">升级条件</view>
<view class="condition-value">{{ level.condition }}</view>
</view>
</view>
<view class="level-benefit">
<view class="benefit-item">
<view class="benefit-label">分销佣金比例</view>
<view class="benefit-value">{{ level.commissionRate }}%</view>
</view>
<view class="benefit-item">
<view class="benefit-label">自购优惠比例</view>
<view class="benefit-value">{{ level.selfBuyRate }}%</view>
</view>
<view class="benefit-item">
<view class="benefit-label">邀请奖励</view>
<view class="benefit-value">¥{{ level.inviteReward.toFixed(2) }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 佣金规则 -->
<view class="rule-section">
<view class="section-title">佣金规则</view>
<view class="rule-card">
<view class="rule-row">
<view class="rule-label">佣金计算方式</view>
<view class="rule-control">
<picker
:range="commissionTypeOptions"
:value="commissionTypeIndex"
@change="onCommissionTypeChange"
class="picker"
>
<view class="picker-text">{{ commissionTypeOptions[commissionTypeIndex] }}</view>
</picker>
</view>
</view>
<view class="rule-row">
<view class="rule-label">佣金结算周期</view>
<view class="rule-control">
<picker
:range="settlementCycleOptions"
:value="settlementCycleIndex"
@change="onSettlementCycleChange"
class="picker"
>
<view class="picker-text">{{ settlementCycleOptions[settlementCycleIndex] }}</view>
</picker>
</view>
</view>
<view class="rule-row">
<view class="rule-label">最低提现金额</view>
<view class="rule-control">
<input
v-model="ruleForm.minWithdrawAmount"
type="number"
class="form-input"
placeholder="请输入最低提现金额"
/>
</view>
</view>
<view class="rule-row">
<view class="rule-label">提现手续费</view>
<view class="rule-control">
<input
v-model="ruleForm.withdrawFee"
type="number"
class="form-input"
placeholder="请输入提现手续费比例"
/>
<view class="input-suffix">%</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from "vue"
// 规则表单数据
const ruleForm = ref({
needAudit: true,
enableLevel: true,
enableSelfBuy: true,
enableInviteReward: true,
minWithdrawAmount: 100,
withdrawFee: 0.5
})
// 佣金计算方式选项
const commissionTypeOptions = ['按比例', '固定金额']
const commissionTypeIndex = ref(0)
// 结算周期选项
const settlementCycleOptions = ['实时结算', '每日结算', '每周结算', '每月结算']
const settlementCycleIndex = ref(3)
// 等级配置
const levelList = ref([
{
name: '初级分销员',
condition: '邀请1人注册',
commissionRate: 10,
selfBuyRate: 5,
inviteReward: 5
},
{
name: '中级分销员',
condition: '邀请5人注册',
commissionRate: 15,
selfBuyRate: 8,
inviteReward: 8
},
{
name: '高级分销员',
condition: '邀请10人注册',
commissionRate: 20,
selfBuyRate: 10,
inviteReward: 10
}
])
onMounted(() => {
// 实际项目中应从接口获取规则配置
// loadRuleConfig()
})
// 返回上一页
function goBack() {
uni.navigateBack({ delta: 1 })
}
// 保存规则
function saveRule() {
uni.showLoading({ title: '保存中...' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({
title: '保存成功',
icon: 'success'
})
// 实际项目中应调用接口保存规则配置
// saveRuleConfig()
}, 1500)
}
// 审核开关变更
function onAuditChange(e) {
const value = e.detail.value
ruleForm.value.needAudit = value
}
// 等级制度开关变更
function onLevelChange(e) {
const value = e.detail.value
ruleForm.value.enableLevel = value
}
// 自购优惠开关变更
function onSelfBuyChange(e) {
const value = e.detail.value
ruleForm.value.enableSelfBuy = value
}
// 邀请奖励开关变更
function onInviteRewardChange(e) {
const value = e.detail.value
ruleForm.value.enableInviteReward = value
}
// 佣金计算方式变更
function onCommissionTypeChange(e) {
const value = e.detail.value
commissionTypeIndex.value = value
}
// 结算周期变更
function onSettlementCycleChange(e) {
const value = e.detail.value
settlementCycleIndex.value = value
}
</script>
<style lang="scss" scoped>
/* #ifndef APP-NVUE */
page {
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: #f5f7fa;
min-height: 100%;
height: auto;
}
view {
font-size: 14px;
line-height: inherit;
}
/* #endif */
.distributor-rule-container {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部 */
.page-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 120rpx;
background-color: #fff;
padding: 0 32rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.header-left {
width: 60rpx;
}
.back-icon {
font-size: 40rpx;
color: #303133;
cursor: pointer;
}
.header-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
}
.header-right {
width: 60rpx;
text-align: right;
}
.save-btn {
font-size: 24rpx;
color: #409eff;
font-weight: 600;
cursor: pointer;
}
/* 规则配置 */
.rule-section {
padding: 32rpx;
background-color: #fff;
margin: 0 16rpx 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #303133;
margin-bottom: 24rpx;
padding-left: 12rpx;
border-left: 8rpx solid #409eff;
line-height: 1.2;
}
.rule-card {
background-color: #f9f9f9;
border-radius: 12rpx;
padding: 24rpx;
}
.rule-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
}
.rule-row:last-child {
margin-bottom: 0;
}
.rule-label {
font-size: 24rpx;
color: #606266;
}
.rule-control {
position: relative;
}
.switch {
transform: scale(0.8);
}
.picker {
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
display: flex;
justify-content: space-between;
align-items: center;
min-width: 200rpx;
}
.picker-text {
font-size: 24rpx;
color: #303133;
}
.form-input {
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
font-size: 24rpx;
color: #303133;
min-width: 150rpx;
}
.input-suffix {
position: absolute;
right: 32rpx;
top: 50%;
transform: translateY(-50%);
font-size: 24rpx;
color: #606266;
}
/* 等级配置 */
.level-config {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.level-item {
background-color: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 16rpx;
}
.level-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
}
.level-title {
font-size: 24rpx;
font-weight: 600;
color: #303133;
}
.level-condition {
display: flex;
align-items: center;
}
.condition-label {
font-size: 18rpx;
color: #606266;
}
.condition-value {
font-size: 18rpx;
color: #409eff;
margin-left: 4rpx;
}
.level-benefit {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.benefit-item {
display: flex;
align-items: center;
}
.benefit-label {
font-size: 18rpx;
color: #606266;
}
.benefit-value {
font-size: 18rpx;
color: #303133;
margin-left: 4rpx;
}
/* 平板和大屏响应式 */
@media screen and (min-width: 768px) {
.distributor-rule-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.rule-section {
margin: 0 32rpx 24rpx;
padding: 40rpx;
}
.section-title {
font-size: 36rpx;
margin-bottom: 32rpx;
}
.rule-card {
padding: 32rpx;
}
.rule-row {
margin-bottom: 32rpx;
}
.rule-label {
font-size: 26rpx;
}
.switch {
transform: scale(1);
}
.picker {
min-width: 250rpx;
padding: 20rpx;
}
.picker-text {
font-size: 26rpx;
}
.form-input {
min-width: 200rpx;
padding: 20rpx;
font-size: 26rpx;
}
.input-suffix {
font-size: 26rpx;
right: 40rpx;
}
.level-item {
padding: 24rpx;
}
.level-title {
font-size: 28rpx;
}
.condition-label,
.benefit-label {
font-size: 20rpx;
}
.condition-value,
.benefit-value {
font-size: 20rpx;
}
.save-btn {
font-size: 28rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.distributor-rule-container {
max-width: 1000px;
}
.section-title {
font-size: 40rpx;
}
.rule-label {
font-size: 28rpx;
}
.picker {
min-width: 300rpx;
}
.picker-text {
font-size: 28rpx;
}
.form-input {
min-width: 250rpx;
font-size: 28rpx;
}
.input-suffix {
font-size: 28rpx;
}
.level-title {
font-size: 32rpx;
}
.condition-label,
.benefit-label {
font-size: 22rpx;
}
.condition-value,
.benefit-value {
font-size: 22rpx;
}
}
</style>

View File

@@ -149,7 +149,7 @@
const unitIndex = ref(0)
// 包含权益
const rights = ref(useTenantStore().tenantInfo?.memberBenefits || [])
const rights = ref(useTenantStore().tenantInfo?.memberBenefitList || [])
const loading = ref(false)
// 编辑模式

View File

@@ -113,7 +113,7 @@
{ value: '1002', label: '摩托车' }
]
const rights = useTenantStore().tenantInfo?.memberBenefits || []
const rights = useTenantStore().tenantInfo?.memberBenefitList || []
// 生命周期
onShow(() => {
getMemberList()

View File

@@ -1,716 +0,0 @@
<template>
<view class="container">
<view class="page-body uni-content-info">
<view class='cropper-content'>
<view v-if="isShowImg" class="uni-corpper" :style="'width:'+cropperInitW+'px;height:'+cropperInitH+'px;background:#000'">
<view class="uni-corpper-content" :style="'width:'+cropperW+'px;height:'+cropperH+'px;left:'+cropperL+'px;top:'+cropperT+'px'">
<image :src="imageSrc" :style="'width:'+cropperW+'px;height:'+cropperH+'px'"></image>
<view class="uni-corpper-crop-box" @touchstart.stop="contentStartMove" @touchmove.stop="contentMoveing" @touchend.stop="contentTouchEnd"
:style="'left:'+cutL+'px;top:'+cutT+'px;right:'+cutR+'px;bottom:'+cutB+'px'">
<view class="uni-cropper-view-box">
<view class="uni-cropper-dashed-h"></view>
<view class="uni-cropper-dashed-v"></view>
<view class="uni-cropper-line-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-line-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-t" data-drag="top" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-tr" data-drag="topTight"></view>
<view class="uni-cropper-point point-r" data-drag="right" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-b" data-drag="bottom" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-bl" data-drag="bottomLeft"></view>
<view class="uni-cropper-point point-l" data-drag="left" @touchstart.stop="dragStart" @touchmove.stop="dragMove"></view>
<view class="uni-cropper-point point-lt" data-drag="leftTop"></view>
</view>
</view>
</view>
</view>
</view>
<view class='cropper-config'>
<button type="primary reverse" @click="getImage" style='margin-top: 30rpx;'> 选择头像 </button>
<button type="warn" @click="getImageInfo" style='margin-top: 30rpx;'> 提交 </button>
</view>
<canvas canvas-id="myCanvas" :style="'position:absolute;border: 1px solid red; width:'+imageW+'px;height:'+imageH+'px;top:-9999px;left:-9999px;'"></canvas>
</view>
</view>
</template>
<script>
import config from '@/config'
import { useUserStore } from '@/store'
import { uploadAvatar } from "@/api/system/user"
const baseUrl = config.baseUrl
let sysInfo = uni.getSystemInfoSync()
let SCREEN_WIDTH = sysInfo.screenWidth
let PAGE_X, // 手按下的x位置
PAGE_Y, // 手按下y的位置
PR = sysInfo.pixelRatio, // dpi
T_PAGE_X, // 手移动的时候x的位置
T_PAGE_Y, // 手移动的时候Y的位置
CUT_L, // 初始化拖拽元素的left值
CUT_T, // 初始化拖拽元素的top值
CUT_R, // 初始化拖拽元素的
CUT_B, // 初始化拖拽元素的
CUT_W, // 初始化拖拽元素的宽度
CUT_H, // 初始化拖拽元素的高度
IMG_RATIO, // 图片比例
IMG_REAL_W, // 图片实际的宽度
IMG_REAL_H, // 图片实际的高度
DRAFG_MOVE_RATIO = 1, //移动时候的比例,
INIT_DRAG_POSITION = 100, // 初始化屏幕宽度和裁剪区域的宽度之差,用于设置初始化裁剪的宽度
DRAW_IMAGE_W = sysInfo.screenWidth // 设置生成的图片宽度
export default {
/**
* 页面的初始数据
*/
data() {
return {
imageSrc: useUserStore().avatar,
isShowImg: false,
// 初始化的宽高
cropperInitW: SCREEN_WIDTH,
cropperInitH: SCREEN_WIDTH,
// 动态的宽高
cropperW: SCREEN_WIDTH,
cropperH: SCREEN_WIDTH,
// 动态的left top值
cropperL: 0,
cropperT: 0,
transL: 0,
transT: 0,
// 图片缩放值
scaleP: 0,
imageW: 0,
imageH: 0,
// 裁剪框 宽高
cutL: 0,
cutT: 0,
cutB: SCREEN_WIDTH,
cutR: '100%',
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: DRAFG_MOVE_RATIO
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
this.loadImage()
},
methods: {
setData: function (obj) {
let that = this
Object.keys(obj).forEach(function (key) {
that.$set(that.$data, key, obj[key])
})
},
getImage: function () {
var _this = this
uni.chooseImage({
success: function (res) {
_this.setData({
imageSrc: res.tempFilePaths[0],
})
_this.loadImage()
},
})
},
loadImage: function () {
var _this = this
uni.getImageInfo({
src: _this.imageSrc,
success: function success(res) {
IMG_RATIO = 1 / 1
if (IMG_RATIO >= 1) {
IMG_REAL_W = SCREEN_WIDTH
IMG_REAL_H = SCREEN_WIDTH / IMG_RATIO
} else {
IMG_REAL_W = SCREEN_WIDTH * IMG_RATIO
IMG_REAL_H = SCREEN_WIDTH
}
let minRange = IMG_REAL_W > IMG_REAL_H ? IMG_REAL_W : IMG_REAL_H
INIT_DRAG_POSITION = minRange > INIT_DRAG_POSITION ? INIT_DRAG_POSITION : minRange
// 根据图片的宽高显示不同的效果 保证图片可以正常显示
if (IMG_RATIO >= 1) {
let cutT = Math.ceil((SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - INIT_DRAG_POSITION)) / 2)
let cutB = cutT
let cutL = Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH + INIT_DRAG_POSITION) / 2)
let cutR = cutL
_this.setData({
cropperW: SCREEN_WIDTH,
cropperH: SCREEN_WIDTH / IMG_RATIO,
// 初始化left right
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2),
cutL: cutL,
cutT: cutT,
cutR: cutR,
cutB: cutB,
// 图片缩放值
imageW: IMG_REAL_W,
imageH: IMG_REAL_H,
scaleP: IMG_REAL_W / SCREEN_WIDTH,
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: IMG_RATIO
})
} else {
let cutL = Math.ceil((SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO)) / 2)
let cutR = cutL
let cutT = Math.ceil((SCREEN_WIDTH - INIT_DRAG_POSITION) / 2)
let cutB = cutT
_this.setData({
cropperW: SCREEN_WIDTH * IMG_RATIO,
cropperH: SCREEN_WIDTH,
// 初始化left right
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2),
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
cutL: cutL,
cutT: cutT,
cutR: cutR,
cutB: cutB,
// 图片缩放值
imageW: IMG_REAL_W,
imageH: IMG_REAL_H,
scaleP: IMG_REAL_W / SCREEN_WIDTH,
qualityWidth: DRAW_IMAGE_W,
innerAspectRadio: IMG_RATIO
})
}
_this.setData({
isShowImg: true
})
uni.hideLoading()
}
})
},
// 拖动时候触发的touchStart事件
contentStartMove(e) {
PAGE_X = e.touches[0].pageX
PAGE_Y = e.touches[0].pageY
},
// 拖动时候触发的touchMove事件
contentMoveing(e) {
var _this = this
var dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
var dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
// 左移
if (dragLengthX > 0) {
if (this.cutL - dragLengthX < 0) dragLengthX = this.cutL
} else {
if (this.cutR + dragLengthX < 0) dragLengthX = -this.cutR
}
if (dragLengthY > 0) {
if (this.cutT - dragLengthY < 0) dragLengthY = this.cutT
} else {
if (this.cutB + dragLengthY < 0) dragLengthY = -this.cutB
}
this.setData({
cutL: this.cutL - dragLengthX,
cutT: this.cutT - dragLengthY,
cutR: this.cutR + dragLengthX,
cutB: this.cutB + dragLengthY
})
PAGE_X = e.touches[0].pageX
PAGE_Y = e.touches[0].pageY
},
contentTouchEnd() {
},
// 获取图片
getImageInfo() {
var _this = this
uni.showLoading({
title: '图片生成中...',
})
// 将图片写入画布
const ctx = uni.createCanvasContext('myCanvas')
ctx.drawImage(_this.imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H)
ctx.draw(true, () => {
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题 canvasT = (_this.cutT / _this.cropperH) * (_this.imageH / pixelRatio)
var canvasW = ((_this.cropperW - _this.cutL - _this.cutR) / _this.cropperW) * IMG_REAL_W
var canvasH = ((_this.cropperH - _this.cutT - _this.cutB) / _this.cropperH) * IMG_REAL_H
var canvasL = (_this.cutL / _this.cropperW) * IMG_REAL_W
var canvasT = (_this.cutT / _this.cropperH) * IMG_REAL_H
uni.canvasToTempFilePath({
x: canvasL,
y: canvasT,
width: canvasW,
height: canvasH,
destWidth: canvasW,
destHeight: canvasH,
quality: 0.5,
canvasId: 'myCanvas',
success: function (res) {
uni.hideLoading()
let data = {name: 'avatarfile', filePath: res.tempFilePath}
uploadAvatar(data).then(response => {
useUserStore().SET_AVATAR(baseUrl + response.imgUrl)
uni.showToast({ title: "修改成功", icon: 'success' })
uni.navigateBack()
})
}
})
})
},
// 设置大小的时候触发的touchStart事件
dragStart(e) {
T_PAGE_X = e.touches[0].pageX
T_PAGE_Y = e.touches[0].pageY
CUT_L = this.cutL
CUT_R = this.cutR
CUT_B = this.cutB
CUT_T = this.cutT
},
// 设置大小的时候触发的touchMove事件
dragMove(e) {
var _this = this
var dragType = e.target.dataset.drag
switch (dragType) {
case 'right':
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
if (CUT_R + dragLength < 0) dragLength = -CUT_R
this.setData({
cutR: CUT_R + dragLength
})
break
case 'left':
var dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
if (CUT_L - dragLength < 0) dragLength = CUT_L
if ((CUT_L - dragLength) > (this.cropperW - this.cutR)) dragLength = CUT_L - (this.cropperW - this.cutR)
this.setData({
cutL: CUT_L - dragLength
})
break
case 'top':
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_T - dragLength < 0) dragLength = CUT_T
if ((CUT_T - dragLength) > (this.cropperH - this.cutB)) dragLength = CUT_T - (this.cropperH - this.cutB)
this.setData({
cutT: CUT_T - dragLength
})
break
case 'bottom':
var dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_B + dragLength < 0) dragLength = -CUT_B
this.setData({
cutB: CUT_B + dragLength
})
break
case 'rightBottom':
var dragLengthX = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
var dragLengthY = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
if (CUT_B + dragLengthY < 0) dragLengthY = -CUT_B
if (CUT_R + dragLengthX < 0) dragLengthX = -CUT_R
let cutB = CUT_B + dragLengthY
let cutR = CUT_R + dragLengthX
this.setData({
cutB: cutB,
cutR: cutR
})
break
default:
break
}
}
}
}
</script>
<style scoped>
.container {
min-height: 100vh;
background-color: #f8f8f8;
}
.page-body {
padding: 24rpx;
}
.cropper-content {
min-height: 750rpx;
width: 100%;
background-color: #fff;
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
.cropper-config {
padding: 20rpx 40rpx;
text-align: center;
}
.cropper-config button {
font-size: 28rpx;
height: 88rpx;
margin-top: 30rpx;
border-radius: 12rpx;
}
.uni-corpper {
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
box-sizing: border-box;
}
.uni-corpper-content {
position: relative;
}
.uni-corpper-content image {
display: block;
width: 100%;
min-width: 0 !important;
max-width: none !important;
height: 100%;
min-height: 0 !important;
max-height: none !important;
image-orientation: 0deg !important;
margin: 0 auto;
}
/* 移动图片效果 */
.uni-cropper-drag-box {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
cursor: move;
background: rgba(0, 0, 0, 0.6);
z-index: 1;
}
/* 内部的信息 */
.uni-corpper-crop-box {
position: absolute;
background: rgba(255, 255, 255, 0.3);
z-index: 2;
}
.uni-corpper-crop-box .uni-cropper-view-box {
position: relative;
display: block;
width: 100%;
height: 100%;
overflow: visible;
outline: 1rpx solid #69f;
outline-color: rgba(102, 153, 255, .75)
}
/* 横向虚线 */
.uni-cropper-dashed-h {
position: absolute;
top: 33.33333333%;
left: 0;
width: 100%;
height: 33.33333333%;
border-top: 1rpx dashed rgba(255, 255, 255, 0.5);
border-bottom: 1rpx dashed rgba(255, 255, 255, 0.5);
}
/* 纵向虚线 */
.uni-cropper-dashed-v {
position: absolute;
left: 33.33333333%;
top: 0;
width: 33.33333333%;
height: 100%;
border-left: 1rpx dashed rgba(255, 255, 255, 0.5);
border-right: 1rpx dashed rgba(255, 255, 255, 0.5);
}
/* 四个方向的线 为了之后的拖动事件*/
.uni-cropper-line-t {
position: absolute;
display: block;
width: 100%;
background-color: #69f;
top: 0;
left: 0;
height: 1rpx;
opacity: 0.1;
cursor: n-resize;
}
.uni-cropper-line-t::before {
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.uni-cropper-line-r {
position: absolute;
display: block;
background-color: #69f;
top: 0;
right: 0rpx;
width: 1rpx;
opacity: 0.1;
height: 100%;
cursor: e-resize;
}
.uni-cropper-line-r::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.uni-cropper-line-b {
position: absolute;
display: block;
width: 100%;
background-color: #69f;
bottom: 0;
left: 0;
height: 1rpx;
opacity: 0.1;
cursor: s-resize;
}
.uni-cropper-line-b::before {
content: '';
position: absolute;
top: 50%;
right: 0rpx;
width: 100%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
bottom: 0;
height: 41rpx;
background: transparent;
z-index: 11;
}
.uni-cropper-line-l {
position: absolute;
display: block;
background-color: #69f;
top: 0;
left: 0;
width: 1rpx;
opacity: 0.1;
height: 100%;
cursor: w-resize;
}
.uni-cropper-line-l::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 41rpx;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
bottom: 0;
height: 100%;
background: transparent;
z-index: 11;
}
.uni-cropper-point {
width: 5rpx;
height: 5rpx;
background-color: #69f;
opacity: .75;
position: absolute;
z-index: 3;
}
.point-t {
top: -3rpx;
left: 50%;
margin-left: -3rpx;
cursor: n-resize;
}
.point-tr {
top: -3rpx;
left: 100%;
margin-left: -3rpx;
cursor: n-resize;
}
.point-r {
top: 50%;
left: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-rb {
left: 100%;
top: 100%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
cursor: n-resize;
width: 36rpx;
height: 36rpx;
background-color: #69f;
position: absolute;
z-index: 1112;
opacity: 1;
}
.point-b {
left: 50%;
top: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-bl {
left: 0%;
top: 100%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-l {
left: 0%;
top: 50%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
.point-lt {
left: 0%;
top: 0%;
margin-left: -3rpx;
margin-top: -3rpx;
cursor: n-resize;
}
/* 裁剪框预览内容 */
.uni-cropper-viewer {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.uni-cropper-viewer image {
position: absolute;
z-index: 2;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.container {
max-width: 900px;
margin: 0 auto;
width: 100%;
background-color: #fff;
}
.page-body {
padding: 32rpx;
}
.cropper-content {
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
.cropper-config {
padding: 40rpx;
}
.cropper-config button {
font-size: 32rpx;
height: 96rpx;
margin-top: 40rpx;
border-radius: 16rpx;
}
.uni-cropper-point {
width: 8rpx;
height: 8rpx;
}
.point-rb {
width: 44rpx;
height: 44rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.container {
max-width: 1000px;
}
.page-body {
padding: 48rpx;
}
.cropper-content {
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
.cropper-config {
padding: 60rpx;
}
.cropper-config button {
font-size: 36rpx;
height: 112rpx;
margin-top: 50rpx;
border-radius: 20rpx;
}
.uni-cropper-point {
width: 10rpx;
height: 10rpx;
}
.point-rb {
width: 52rpx;
height: 52rpx;
}
}
</style>

View File

@@ -1,198 +0,0 @@
<template>
<view class="help-container">
<view v-for="(item, findex) in list" :key="findex" :title="item.title" class="list-title">
<view class="text-title">
<view :class="item.icon"></view>{{ item.title }}
</view>
<view class="childList">
<view v-for="(child, zindex) in item.childList" :key="zindex" class="question" hover-class="hover"
@click="handleText(child)">
<view class="text-item">{{ child.title }}</view>
<view class="line" v-if="zindex !== item.childList.length - 1"></view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, getCurrentInstance } from "vue"
const { proxy } = getCurrentInstance()
const list = ref([{
icon: 'iconfont icon-github',
title: '若依问题',
childList: [{
title: '若依开源吗?',
content: '开源'
}, {
title: '若依可以商用吗?',
content: '可以'
}, {
title: '若依官网地址多少?',
content: 'http://ruoyi.vip'
}, {
title: '若依文档地址多少?',
content: 'http://doc.ruoyi.vip'
}]
},
{
icon: 'iconfont icon-help',
title: '其他问题',
childList: [{
title: '如何退出登录?',
content: '请点击[我的] - [应用设置] - [退出登录]即可退出登录',
}, {
title: '如何修改用户头像?',
content: '请点击[我的] - [选择头像] - [点击提交]即可更换用户头像',
}, {
title: '如何修改登录密码?',
content: '请点击[我的] - [应用设置] - [修改密码]即可修改登录密码',
}]
}])
function handleText(item) {
proxy.$tab.navigateTo(`/pages/common/textview/index?title=${item.title}&content=${item.content}`)
}
</script>
<style lang="scss" scoped>
page {
background-color: #f8f8f8;
}
.help-container {
min-height: 100vh;
margin-bottom: 100rpx;
padding: 24rpx;
}
.list-title {
margin-bottom: 30rpx;
}
.text-title {
color: #303133;
font-size: 32rpx;
font-weight: bold;
margin-left: 10rpx;
line-height: 1.4;
display: flex;
align-items: center;
.iconfont {
font-size: 16px;
margin-right: 10rpx;
color: #409eff;
}
}
.childList {
background: #ffffff;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
border-radius: 16rpx;
margin-top: 16rpx;
overflow: hidden;
}
.question {
color: #606266;
font-size: 28rpx;
transition: all 0.3s ease;
}
.question:hover {
background-color: #f5f7fa;
}
.text-item {
font-size: 28rpx;
padding: 24rpx;
line-height: 1.4;
}
.line {
width: 100%;
height: 1rpx;
background-color: #F5F5F5;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.help-container {
max-width: 900px;
margin: 0 auto 100rpx;
width: 100%;
background-color: #fff;
padding: 40rpx;
border-radius: 0;
}
.list-title {
margin-bottom: 40rpx;
}
.text-title {
font-size: 36rpx;
margin-left: 16rpx;
.iconfont {
font-size: 20px;
margin-right: 16rpx;
}
}
.childList {
margin-top: 20rpx;
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
.question {
font-size: 32rpx;
}
.text-item {
font-size: 32rpx;
padding: 32rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.help-container {
max-width: 1000px;
padding: 60rpx;
}
.list-title {
margin-bottom: 50rpx;
}
.text-title {
font-size: 40rpx;
margin-left: 20rpx;
.iconfont {
font-size: 24px;
margin-right: 20rpx;
}
}
.childList {
margin-top: 24rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
.question {
font-size: 36rpx;
}
.text-item {
font-size: 36rpx;
padding: 40rpx;
}
}
</style>

View File

@@ -1,292 +0,0 @@
<template>
<view class="container">
<view class="example">
<uni-forms ref="form" :model="user" labelWidth="80px">
<uni-forms-item label="用户昵称" name="nickName">
<uni-easyinput v-model="user.nickName" placeholder="请输入昵称" />
</uni-forms-item>
<uni-forms-item label="手机号码" name="phonenumber">
<uni-easyinput v-model="user.phonenumber" placeholder="请输入手机号码" />
</uni-forms-item>
<uni-forms-item label="邮箱" name="email">
<uni-easyinput v-model="user.email" placeholder="请输入邮箱" />
</uni-forms-item>
<uni-forms-item label="性别" name="sex" required>
<uni-data-checkbox v-model="user.sex" :localdata="sexs" />
</uni-forms-item>
</uni-forms>
<button type="primary" @click="submit">提交</button>
</view>
</view>
</template>
<script setup>
import { getUserProfile } from "@/api/system/user"
import { updateUserProfile } from "@/api/system/user"
import { ref , getCurrentInstance } from "vue"
import { onReady } from "@dcloudio/uni-app"
const { proxy } = getCurrentInstance()
const user = ref({
nickName: "",
phonenumber: "",
email: "",
sex: ""
})
const sexs = [{
text: '男',
value: "0"
}, {
text: '女',
value: "1"
}]
const rules = ref({
nickName: {
rules: [{
required: true,
errorMessage: '用户昵称不能为空'
}]
},
phonenumber: {
rules: [{
required: true,
errorMessage: '手机号码不能为空'
}, {
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
errorMessage: '请输入正确的手机号码'
}]
},
email: {
rules: [{
required: true,
errorMessage: '邮箱地址不能为空'
}, {
format: 'email',
errorMessage: '请输入正确的邮箱地址'
}]
}
})
function getUser() {
getUserProfile().then(response => {
user.value = response.data
})
}
function submit(ref) {
proxy.$refs.form.validate().then(res => {
updateUserProfile(user.value).then(response => {
proxy.$modal.msgSuccess("修改成功")
})
})
}
onReady(() => {
proxy.$refs.form.setRules(rules.value)
})
getUser()
</script>
<style lang="scss" scoped>
page {
background-color: #f5f7fa;
}
.container {
min-height: 100vh;
}
.example {
background-color: #fff;
padding: 24rpx;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
/* 表单样式 */
:deep(.uni-forms) {
width: 100%;
}
:deep(.uni-forms-item) {
margin-bottom: 32rpx;
}
:deep(.uni-forms-label) {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
:deep(.uni-easyinput__input) {
font-size: 28rpx;
height: 88rpx;
padding: 0 24rpx;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
color: #303133;
background-color: #f9f9f9;
}
:deep(.uni-easyinput__input:focus) {
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
:deep(.uni-data-checkbox) {
font-size: 28rpx;
}
:deep(.uni-data-checkbox__list) {
margin-top: 12rpx;
}
:deep(.uni-data-checkbox__item) {
margin-right: 32rpx;
display: flex;
align-items: center;
}
:deep(.uni-data-checkbox__input) {
width: 24rpx;
height: 24rpx;
margin-right: 8rpx;
}
/* 按钮样式 */
button {
font-size: 28rpx;
height: 88rpx;
margin-top: 40rpx;
border-radius: 12rpx;
background-color: #409eff;
color: #fff;
font-weight: 500;
}
button:hover {
background-color: #66b1ff;
}
button:active {
background-color: #3a8ee6;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
.example {
margin: 24rpx;
padding: 40rpx;
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
/* 表单样式 */
:deep(.uni-forms-item) {
margin-bottom: 40rpx;
}
:deep(.uni-forms-label) {
font-size: 32rpx;
width: 140px;
}
:deep(.uni-easyinput__input) {
font-size: 32rpx;
height: 96rpx;
padding: 0 32rpx;
border-radius: 12rpx;
}
:deep(.uni-data-checkbox) {
font-size: 32rpx;
}
:deep(.uni-data-checkbox__list) {
margin-top: 16rpx;
}
:deep(.uni-data-checkbox__item) {
margin-right: 40rpx;
}
:deep(.uni-data-checkbox__input) {
width: 28rpx;
height: 28rpx;
margin-right: 12rpx;
}
/* 按钮样式 */
button {
font-size: 32rpx;
height: 96rpx;
margin-top: 50rpx;
border-radius: 16rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.container {
max-width: 1000px;
}
.example {
margin: 32rpx;
padding: 48rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
/* 表单样式 */
:deep(.uni-forms-item) {
margin-bottom: 48rpx;
}
:deep(.uni-forms-label) {
font-size: 36rpx;
width: 160px;
}
:deep(.uni-easyinput__input) {
font-size: 36rpx;
height: 112rpx;
padding: 0 40rpx;
border-radius: 16rpx;
}
:deep(.uni-data-checkbox) {
font-size: 36rpx;
}
:deep(.uni-data-checkbox__list) {
margin-top: 20rpx;
}
:deep(.uni-data-checkbox__item) {
margin-right: 50rpx;
}
:deep(.uni-data-checkbox__input) {
width: 32rpx;
height: 32rpx;
margin-right: 16rpx;
}
/* 按钮样式 */
button {
font-size: 36rpx;
height: 112rpx;
margin-top: 60rpx;
border-radius: 20rpx;
}
}
</style>

View File

@@ -1,146 +0,0 @@
<template>
<view class="container">
<uni-list>
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'person-filled'}" title="昵称" :rightText="user.nickName" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'phone-filled'}" title="手机号码" :rightText="user.phonenumber" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'email-filled'}" title="邮箱" :rightText="user.email" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'auth-filled'}" title="岗位" :rightText="postGroup" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'staff-filled'}" title="角色" :rightText="roleGroup" />
<uni-list-item showExtraIcon="true" :extraIcon="{type: 'calendar-filled'}" title="创建日期" :rightText="user.createTime" />
</uni-list>
</view>
</template>
<script setup>
import { getUserProfile } from "@/api/system/user"
import { ref, reactive } from "vue"
const user = ref({})
const roleGroup = ref("")
const postGroup = ref("")
function getUser() {
getUserProfile().then(response => {
user.value = response.data
roleGroup.value = response.roleGroup
postGroup.value = response.postGroup
})
}
getUser()
</script>
<style lang="scss" scoped>
page {
background-color: #f5f7fa;
}
.container {
min-height: 100vh;
}
/* 列表样式 */
:deep(.uni-list) {
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
}
:deep(.uni-list-item) {
padding: 28rpx;
font-size: 28rpx;
border-bottom: 1rpx solid #f0f0f0;
transition: all 0.3s ease;
}
:deep(.uni-list-item:last-child) {
border-bottom: none;
}
:deep(.uni-list-item__content) {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
:deep(.uni-list-item__extra) {
font-size: 26rpx;
color: #606266;
text-align: right;
flex: 1;
margin-left: 24rpx;
}
:deep(.uni-list-item__icon) {
font-size: 32rpx;
color: #409eff;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
/* 列表样式 */
:deep(.uni-list) {
margin: 24rpx;
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
:deep(.uni-list-item) {
padding: 32rpx;
font-size: 32rpx;
}
:deep(.uni-list-item__content) {
font-size: 32rpx;
}
:deep(.uni-list-item__extra) {
font-size: 30rpx;
margin-left: 32rpx;
}
:deep(.uni-list-item__icon) {
font-size: 36rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.container {
max-width: 1000px;
}
/* 列表样式 */
:deep(.uni-list) {
margin: 32rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
:deep(.uni-list-item) {
padding: 40rpx;
font-size: 36rpx;
}
:deep(.uni-list-item__content) {
font-size: 36rpx;
}
:deep(.uni-list-item__extra) {
font-size: 34rpx;
margin-left: 40rpx;
}
:deep(.uni-list-item__icon) {
font-size: 40rpx;
}
}
</style>

View File

@@ -105,17 +105,6 @@
uni.navigateBack({ delta: 1 })
}
// 获取性别索引
function getGenderIndex() {
return genders.indexOf(userInfo.value.gender)
}
// 处理性别变更
function onGenderChange(e) {
const index = e.detail.value
userInfo.value.gender = genders[index]
}
// 选择头像
function chooseAvatar() {
uni.chooseImage({

View File

@@ -1,211 +0,0 @@
<template>
<view class="pwd-retrieve-container">
<uni-forms ref="form" :value="user" labelWidth="80px">
<uni-forms-item name="oldPassword" label="旧密码">
<uni-easyinput type="password" v-model="user.oldPassword" placeholder="请输入旧密码" />
</uni-forms-item>
<uni-forms-item name="newPassword" label="新密码">
<uni-easyinput type="password" v-model="user.newPassword" placeholder="请输入新密码" />
</uni-forms-item>
<uni-forms-item name="confirmPassword" label="确认密码">
<uni-easyinput type="password" v-model="user.confirmPassword" placeholder="请确认新密码" />
</uni-forms-item>
<button type="primary" @click="submit">提交</button>
</uni-forms>
</view>
</template>
<script setup>
import { updateUserPwd } from "@/api/system/user"
import { ref, reactive , getCurrentInstance } from "vue"
import { onReady } from "@dcloudio/uni-app"
const { proxy } = getCurrentInstance()
const user = reactive({
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
})
const rules = ref({
oldPassword: {
rules: [{
required: true,
errorMessage: '旧密码不能为空'
}]
},
newPassword: {
rules: [{
required: true,
errorMessage: '新密码不能为空',
}, {
minLength: 6,
maxLength: 20,
errorMessage: '长度在 6 到 20 个字符'
}]
},
confirmPassword: {
rules: [{
required: true,
errorMessage: '确认密码不能为空'
}, {
validateFunction: (rule, value, data) => user.newPassword === value,
errorMessage: '两次输入的密码不一致'
}]
}
})
onReady(() => {
proxy.$refs.form.setRules(rules.value)
})
function submit() {
proxy.$refs.form.validate().then(res => {
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
proxy.$modal.msgSuccess("修改成功")
})
})
}
</script>
<style lang="scss" scoped>
page {
background-color: #f5f7fa;
}
.pwd-retrieve-container {
min-height: 100vh;
padding: 24rpx;
}
/* 表单样式 */
:deep(.uni-forms) {
background-color: #fff;
padding: 32rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
}
:deep(.uni-forms-item) {
margin-bottom: 32rpx;
}
:deep(.uni-forms-label) {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
:deep(.uni-easyinput__input) {
font-size: 28rpx;
height: 88rpx;
padding: 0 24rpx;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
color: #303133;
background-color: #f9f9f9;
}
:deep(.uni-easyinput__input:focus) {
border-color: #409eff;
box-shadow: 0 0 0 2rpx rgba(64, 158, 255, 0.2);
}
/* 按钮样式 */
button {
font-size: 28rpx;
height: 88rpx;
margin-top: 40rpx;
border-radius: 12rpx;
background-color: #409eff;
color: #fff;
font-weight: 500;
}
button:hover {
background-color: #66b1ff;
}
button:active {
background-color: #3a8ee6;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.pwd-retrieve-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
padding: 40rpx;
}
/* 表单样式 */
:deep(.uni-forms) {
padding: 40rpx;
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
:deep(.uni-forms-item) {
margin-bottom: 40rpx;
}
:deep(.uni-forms-label) {
font-size: 32rpx;
width: 140px;
}
:deep(.uni-easyinput__input) {
font-size: 32rpx;
height: 96rpx;
padding: 0 32rpx;
border-radius: 12rpx;
}
/* 按钮样式 */
button {
font-size: 32rpx;
height: 96rpx;
margin-top: 50rpx;
border-radius: 16rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.pwd-retrieve-container {
max-width: 1000px;
padding: 60rpx;
}
/* 表单样式 */
:deep(.uni-forms) {
padding: 48rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
:deep(.uni-forms-item) {
margin-bottom: 48rpx;
}
:deep(.uni-forms-label) {
font-size: 36rpx;
width: 160px;
}
:deep(.uni-easyinput__input) {
font-size: 36rpx;
height: 112rpx;
padding: 0 40rpx;
border-radius: 16rpx;
}
/* 按钮样式 */
button {
font-size: 36rpx;
height: 112rpx;
margin-top: 60rpx;
border-radius: 20rpx;
}
}
</style>

View File

@@ -1,218 +0,0 @@
<template>
<view class="setting-container" :style="{height: `${windowHeight}px`}">
<view class="menu-list">
<view class="list-cell list-cell-arrow" @click="handleToPwd">
<view class="menu-item-box">
<view class="iconfont icon-password menu-icon"></view>
<view>修改密码</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleToUpgrade">
<view class="menu-item-box">
<view class="iconfont icon-refresh menu-icon"></view>
<view>检查更新</view>
</view>
</view>
<view class="list-cell list-cell-arrow" @click="handleCleanTmp">
<view class="menu-item-box">
<view class="iconfont icon-clean menu-icon"></view>
<view>清理缓存</view>
</view>
</view>
</view>
<view class="cu-list menu">
<view class="cu-item item-box">
<view class="content text-center" @click="handleLogout">
<text class="text-black">退出登录</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { useUserStore } from '@/store'
import { ref, computed , getCurrentInstance } from "vue"
const { proxy } = getCurrentInstance()
const windowHeight = computed(() => uni.getSystemInfoSync().windowHeight - 50)
function handleToPwd() {
proxy.$tab.navigateTo('/pages/mine/pwd/index')
}
function handleToUpgrade() {
proxy.$modal.showToast('模块建设中~')
}
function handleCleanTmp() {
proxy.$modal.showToast('模块建设中~')
}
function handleLogout() {
proxy.$modal.confirm('确定注销并退出系统吗?').then(() => {
useUserStore().logOut().then(() => {}).finally(()=>{
proxy.$tab.reLaunch('/pages/index')
})
})
}
</script>
<style lang="scss" scoped>
page {
background-color: #f5f7fa;
}
.setting-container {
min-height: 100vh;
}
/* 菜单列表样式 */
.menu-list {
background-color: #fff;
margin: 16rpx;
border-radius: 16rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.list-cell {
padding: 28rpx;
border-bottom: 1rpx solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
transition: all 0.3s ease;
}
.list-cell:last-child {
border-bottom: none;
}
.list-cell:active {
background-color: #f5f7fa;
}
.menu-item-box {
display: flex;
align-items: center;
font-size: 28rpx;
color: #303133;
}
.menu-icon {
font-size: 32rpx;
margin-right: 24rpx;
color: #409eff;
}
/* 退出登录按钮样式 */
.cu-list {
margin-top: 40rpx;
}
.item-box {
background-color: #fff;
margin: 16rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 28rpx;
border-radius: 16rpx;
color: #303133;
font-size: 28rpx;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
}
.item-box:active {
background-color: #f5f7fa;
}
.content {
font-size: 28rpx;
color: #303133;
font-weight: 500;
}
/* 平板响应式 */
@media screen and (min-width: 768px) {
.setting-container {
max-width: 900px;
margin: 0 auto;
width: 100%;
}
/* 菜单列表样式 */
.menu-list {
margin: 24rpx;
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
.list-cell {
padding: 32rpx;
}
.menu-item-box {
font-size: 32rpx;
.menu-icon {
font-size: 36rpx;
margin-right: 32rpx;
}
}
/* 退出登录按钮样式 */
.item-box {
margin: 24rpx;
padding: 32rpx;
border-radius: 20rpx;
box-shadow: 0 6rpx 24rpx rgba(0, 0, 0, 0.1);
}
.content {
font-size: 32rpx;
}
}
/* 大屏设备响应式 */
@media screen and (min-width: 1024px) {
.setting-container {
max-width: 1000px;
}
/* 菜单列表样式 */
.menu-list {
margin: 32rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
.list-cell {
padding: 40rpx;
}
.menu-item-box {
font-size: 36rpx;
.menu-icon {
font-size: 40rpx;
margin-right: 40rpx;
}
}
/* 退出登录按钮样式 */
.item-box {
margin: 32rpx;
padding: 40rpx;
border-radius: 24rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.12);
}
.content {
font-size: 36rpx;
}
}
</style>

241
src/static/scss/global.css Normal file
View File

@@ -0,0 +1,241 @@
@charset "UTF-8";
.list-cell-arrow::before {
content: ' ';
height: 10px;
width: 10px;
border-width: 2px 2px 0 0;
border-color: #c0c0c0;
border-style: solid;
-webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
position: absolute;
top: 50%;
margin-top: -6px;
right: 30rpx;
}
.list-cell {
position: relative;
width: 100%;
box-sizing: border-box;
background-color: #fff;
color: #333;
padding: 26rpx 30rpx;
}
.list-cell:first-child {
border-radius: 8rpx 8rpx 0 0;
}
.list-cell:last-child {
border-radius: 0 0 8rpx 8rpx;
}
.list-cell::after {
content: '';
position: absolute;
border-bottom: 1px solid #eaeef1;
-webkit-transform: scaleY(0.5) translateZ(0);
transform: scaleY(0.5) translateZ(0);
transform-origin: 0 100%;
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.menu-list {
margin: 15px 15px;
}
.menu-list .menu-item-box {
width: 100%;
display: flex;
align-items: center;
}
.menu-list .menu-item-box .menu-icon {
color: #007aff;
font-size: 16px;
margin-right: 5px;
}
.menu-list .menu-item-box .text-right {
margin-left: auto;
margin-right: 34rpx;
color: #999;
}
/* 全局Radio样式美化 */
radio {
transform: scale(0.8);
}
radio[checked] .wx-radio-input {
border-color: #409eff !important;
background-color: #409eff !important;
}
/* 全局Checkbox样式美化 */
/* 基础样式重置 */
checkbox {
width: 40rpx !important;
height: 40rpx !important;
margin: 0 !important;
padding: 0 !important;
}
/* Uni-app核心样式覆盖 */
.uni-checkbox-input {
width: 40rpx !important;
height: 40rpx !important;
border: 2rpx solid #dcdfe6 !important;
border-radius: 8rpx !important;
background-color: #ffffff !important;
transition: all 0.3s ease-in-out !important;
position: relative !important;
overflow: hidden !important;
}
.uni-checkbox-input:hover {
border-color: #409eff !important;
box-shadow: 0 0 12rpx rgba(64, 158, 255, 0.2) !important;
}
/* 选中状态 */
.uni-checkbox-input.uni-checkbox-input-checked {
border-color: #409eff !important;
background-color: #409eff !important;
animation: checkboxPulse 0.3s ease-in-out !important;
}
/* 选中状态的对勾 - 使用SVG路径实现 */
.uni-checkbox-input.uni-checkbox-input-checked::after {
content: '' !important;
position: absolute !important;
top: 8rpx !important;
left: 13rpx !important;
width: 12rpx !important;
height: 20rpx !important;
border: 3rpx solid #ffffff !important;
border-top: none !important;
border-left: none !important;
transform: rotate(45deg) !important;
transform-origin: center !important;
animation: checkboxTick 0.3s ease-in-out !important;
}
/* 清除默认对勾 */
.uni-checkbox-input.uni-checkbox-input-checked::before {
display: none !important;
content: none !important;
}
/* 微信小程序兼容 */
checkbox .wx-checkbox-input {
width: 40rpx !important;
height: 40rpx !important;
border: 2rpx solid #dcdfe6 !important;
border-radius: 8rpx !important;
background-color: #ffffff !important;
}
checkbox[checked] .wx-checkbox-input {
border-color: #409eff !important;
background-color: #409eff !important;
}
checkbox[checked] .wx-checkbox-input::before {
display: none !important;
}
/* 禁用状态样式 */
checkbox[disabled] {
opacity: 0.5 !important;
}
checkbox[disabled] .uni-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #f5f7fa !important;
cursor: not-allowed !important;
}
checkbox[disabled] .uni-checkbox-input:hover {
border-color: #dcdfe6 !important;
box-shadow: none !important;
}
checkbox[disabled] .uni-checkbox-input.uni-checkbox-input-checked {
border-color: #dcdfe6 !important;
background-color: #dcdfe6 !important;
}
/* 微信小程序禁用状态 */
checkbox[disabled] .wx-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #f5f7fa !important;
}
checkbox[disabled][checked] .wx-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #dcdfe6 !important;
}
checkbox[checked] .wx-checkbox-input::after {
content: '' !important;
position: absolute !important;
top: 8rpx !important;
left: 13rpx !important;
width: 12rpx !important;
height: 20rpx !important;
border: 3rpx solid #ffffff !important;
border-top: none !important;
border-left: none !important;
transform: rotate(45deg) !important;
}
/* 动画效果 */
@keyframes checkboxPulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
@keyframes checkboxTick {
0% {
transform: rotate(45deg) scale(0);
opacity: 0;
}
100% {
transform: rotate(45deg) scale(1);
opacity: 1;
}
}
/* 通用选择器样式 */
.radio-item,
.checkbox-item {
display: flex;
align-items: center;
cursor: pointer;
transition: color 0.3s ease;
}
.radio-item:hover .radio-label,
.checkbox-item:hover .checkbox-label {
color: #409eff;
}
.radio-label,
.checkbox-label {
margin-left: 8rpx;
font-size: 24rpx;
color: #303133;
transition: color 0.3s ease;
}

1
src/static/scss/global.min.css vendored Normal file
View File

@@ -0,0 +1 @@
.list-cell-arrow::before{content:' ';height:10px;width:10px;border-width:2px 2px 0 0;border-color:#c0c0c0;border-style:solid;-webkit-transform:matrix(0.5, 0.5, -0.5, 0.5, 0, 0);transform:matrix(0.5, 0.5, -0.5, 0.5, 0, 0);position:absolute;top:50%;margin-top:-6px;right:30rpx}.list-cell{position:relative;width:100%;box-sizing:border-box;background-color:#fff;color:#333;padding:26rpx 30rpx}.list-cell:first-child{border-radius:8rpx 8rpx 0 0}.list-cell:last-child{border-radius:0 0 8rpx 8rpx}.list-cell::after{content:'';position:absolute;border-bottom:1px solid #eaeef1;-webkit-transform:scaleY(0.5) translateZ(0);transform:scaleY(0.5) translateZ(0);transform-origin:0 100%;bottom:0;right:0;left:0;pointer-events:none}.menu-list{margin:15px 15px}.menu-list .menu-item-box{width:100%;display:flex;align-items:center}.menu-list .menu-item-box .menu-icon{color:#007aff;font-size:16px;margin-right:5px}.menu-list .menu-item-box .text-right{margin-left:auto;margin-right:34rpx;color:#999}radio{transform:scale(0.8)}radio[checked] .wx-radio-input{border-color:#409eff !important;background-color:#409eff !important}checkbox{width:40rpx !important;height:40rpx !important;margin:0 !important;padding:0 !important}.uni-checkbox-input{width:40rpx !important;height:40rpx !important;border:2rpx solid #dcdfe6 !important;border-radius:8rpx !important;background-color:#ffffff !important;transition:all 0.3s ease-in-out !important;position:relative !important;overflow:hidden !important}.uni-checkbox-input:hover{border-color:#409eff !important;box-shadow:0 0 12rpx rgba(64,158,255,0.2) !important}.uni-checkbox-input.uni-checkbox-input-checked{border-color:#409eff !important;background-color:#409eff !important;animation:checkboxPulse 0.3s ease-in-out !important}.uni-checkbox-input.uni-checkbox-input-checked::after{content:'' !important;position:absolute !important;top:8rpx !important;left:13rpx !important;width:12rpx !important;height:20rpx !important;border:3rpx solid #ffffff !important;border-top:none !important;border-left:none !important;transform:rotate(45deg) !important;transform-origin:center !important;animation:checkboxTick 0.3s ease-in-out !important}.uni-checkbox-input.uni-checkbox-input-checked::before{display:none !important;content:none !important}checkbox .wx-checkbox-input{width:40rpx !important;height:40rpx !important;border:2rpx solid #dcdfe6 !important;border-radius:8rpx !important;background-color:#ffffff !important}checkbox[checked] .wx-checkbox-input{border-color:#409eff !important;background-color:#409eff !important}checkbox[checked] .wx-checkbox-input::before{display:none !important}checkbox[disabled]{opacity:0.5 !important}checkbox[disabled] .uni-checkbox-input{border-color:#dcdfe6 !important;background-color:#f5f7fa !important;cursor:not-allowed !important}checkbox[disabled] .uni-checkbox-input:hover{border-color:#dcdfe6 !important;box-shadow:none !important}checkbox[disabled] .uni-checkbox-input.uni-checkbox-input-checked{border-color:#dcdfe6 !important;background-color:#dcdfe6 !important}checkbox[disabled] .wx-checkbox-input{border-color:#dcdfe6 !important;background-color:#f5f7fa !important}checkbox[disabled][checked] .wx-checkbox-input{border-color:#dcdfe6 !important;background-color:#dcdfe6 !important}checkbox[checked] .wx-checkbox-input::after{content:'' !important;position:absolute !important;top:8rpx !important;left:13rpx !important;width:12rpx !important;height:20rpx !important;border:3rpx solid #ffffff !important;border-top:none !important;border-left:none !important;transform:rotate(45deg) !important}@keyframes checkboxPulse{0%{transform:scale(1)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes checkboxTick{0%{transform:rotate(45deg) scale(0);opacity:0}100%{transform:rotate(45deg) scale(1);opacity:1}}.radio-item,.checkbox-item{display:flex;align-items:center;cursor:pointer;transition:color 0.3s ease}.radio-item:hover .radio-label,.checkbox-item:hover .checkbox-label{color:#409eff}.radio-label,.checkbox-label{margin-left:8rpx;font-size:24rpx;color:#303133;transition:color 0.3s ease}

View File

@@ -1,26 +1,3 @@
.text-center {
text-align: center;
}
.font-13 {
font-size: 13px;
}
.font-12 {
font-size: 12px;
}
.font-11 {
font-size: 11px;
}
.text-grey1 {
color: #888;
}
.text-grey2 {
color: #aaa;
}
.list-cell-arrow::before {
content: ' ';
height: 10px;
@@ -66,7 +43,6 @@
pointer-events: none;
}
.menu-list {
margin: 15px 15px;
@@ -76,7 +52,7 @@
align-items: center;
.menu-icon {
color: #007AFF;
color: #007aff;
font-size: 16px;
margin-right: 5px;
}
@@ -88,3 +64,177 @@
}
}
}
/* 全局Radio样式美化 */
radio {
transform: scale(0.8);
}
radio[checked] .wx-radio-input {
border-color: #409eff !important;
background-color: #409eff !important;
}
/* 全局Checkbox样式美化 */
/* 基础样式重置 */
checkbox {
width: 40rpx !important;
height: 40rpx !important;
margin: 0 !important;
padding: 0 !important;
}
/* Uni-app核心样式覆盖 */
.uni-checkbox-input {
width: 40rpx !important;
height: 40rpx !important;
border: 2rpx solid #dcdfe6 !important;
border-radius: 8rpx !important;
background-color: #ffffff !important;
transition: all 0.3s ease-in-out !important;
position: relative !important;
overflow: hidden !important;
}
.uni-checkbox-input:hover {
border-color: #409eff !important;
box-shadow: 0 0 12rpx rgba(64, 158, 255, 0.2) !important;
}
/* 选中状态 */
.uni-checkbox-input.uni-checkbox-input-checked {
border-color: #409eff !important;
background-color: #409eff !important;
animation: checkboxPulse 0.3s ease-in-out !important;
}
/* 选中状态的对勾 - 使用SVG路径实现 */
.uni-checkbox-input.uni-checkbox-input-checked::after {
content: '' !important;
position: absolute !important;
top: 8rpx !important;
left: 13rpx !important;
width: 12rpx !important;
height: 20rpx !important;
border: 3rpx solid #ffffff !important;
border-top: none !important;
border-left: none !important;
transform: rotate(45deg) !important;
transform-origin: center !important;
animation: checkboxTick 0.3s ease-in-out !important;
}
/* 清除默认对勾 */
.uni-checkbox-input.uni-checkbox-input-checked::before {
display: none !important;
content: none !important;
}
/* 微信小程序兼容 */
checkbox .wx-checkbox-input {
width: 40rpx !important;
height: 40rpx !important;
border: 2rpx solid #dcdfe6 !important;
border-radius: 8rpx !important;
background-color: #ffffff !important;
}
checkbox[checked] .wx-checkbox-input {
border-color: #409eff !important;
background-color: #409eff !important;
}
checkbox[checked] .wx-checkbox-input::before {
display: none !important;
}
/* 禁用状态样式 */
checkbox[disabled] {
opacity: 0.5 !important;
}
checkbox[disabled] .uni-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #f5f7fa !important;
cursor: not-allowed !important;
}
checkbox[disabled] .uni-checkbox-input:hover {
border-color: #dcdfe6 !important;
box-shadow: none !important;
}
checkbox[disabled] .uni-checkbox-input.uni-checkbox-input-checked {
border-color: #dcdfe6 !important;
background-color: #dcdfe6 !important;
}
/* 微信小程序禁用状态 */
checkbox[disabled] .wx-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #f5f7fa !important;
}
checkbox[disabled][checked] .wx-checkbox-input {
border-color: #dcdfe6 !important;
background-color: #dcdfe6 !important;
}
checkbox[checked] .wx-checkbox-input::after {
content: '' !important;
position: absolute !important;
top: 8rpx !important;
left: 13rpx !important;
width: 12rpx !important;
height: 20rpx !important;
border: 3rpx solid #ffffff !important;
border-top: none !important;
border-left: none !important;
transform: rotate(45deg) !important;
}
/* 动画效果 */
@keyframes checkboxPulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
@keyframes checkboxTick {
0% {
transform: rotate(45deg) scale(0);
opacity: 0;
}
100% {
transform: rotate(45deg) scale(1);
opacity: 1;
}
}
/* 通用选择器样式 */
.radio-item,
.checkbox-item {
display: flex;
align-items: center;
cursor: pointer;
transition: color 0.3s ease;
}
.radio-item:hover .radio-label,
.checkbox-item:hover .checkbox-label {
color: #409eff;
}
.radio-label,
.checkbox-label {
margin-left: 8rpx;
font-size: 24rpx;
color: #303133;
transition: color 0.3s ease;
}