调整文件结构;跑通admin端;初步设计页面结构
This commit is contained in:
528
pages/mall/admin/system-settings.uvue
Normal file
528
pages/mall/admin/system-settings.uvue
Normal file
@@ -0,0 +1,528 @@
|
||||
<!-- 系统设置页面 - 基于CRMEB设计 -->
|
||||
<template>
|
||||
<view class="system-settings">
|
||||
<!-- 设置选项卡 -->
|
||||
<view class="settings-tabs">
|
||||
<view class="tab-list">
|
||||
<view
|
||||
v-for="tab in settingTabs"
|
||||
:key="tab.key"
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === tab.key }"
|
||||
@click="switchTab(tab.key)"
|
||||
>
|
||||
<text class="tab-text">{{ tab.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 基础设置 -->
|
||||
<view v-if="activeTab === 'basic'" class="setting-section">
|
||||
<view class="section-title">基础设置</view>
|
||||
<view class="setting-form">
|
||||
<view class="form-item">
|
||||
<text class="label">网站名称:</text>
|
||||
<input v-model="settings.site_name" placeholder="请输入网站名称" class="input-field" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">网站域名:</text>
|
||||
<input v-model="settings.site_domain" placeholder="请输入网站域名" class="input-field" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">网站Logo:</text>
|
||||
<view class="upload-area">
|
||||
<image v-if="settings.site_logo" :src="settings.site_logo" class="logo-preview" />
|
||||
<button class="upload-btn" @click="chooseLogo">选择图片</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">客服电话:</text>
|
||||
<input v-model="settings.service_phone" placeholder="请输入客服电话" class="input-field" />
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">网站描述:</text>
|
||||
<textarea v-model="settings.site_description" placeholder="请输入网站描述" class="textarea-field" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付设置 -->
|
||||
<view v-if="activeTab === 'payment'" class="setting-section">
|
||||
<view class="section-title">支付设置</view>
|
||||
<view class="setting-form">
|
||||
<view class="form-item">
|
||||
<text class="label">微信支付:</text>
|
||||
<view class="switch-item">
|
||||
<switch :checked="settings.wechat_pay_enabled" @change="onWechatPayChange" />
|
||||
<text class="switch-label">{{ settings.wechat_pay_enabled ? '已开启' : '已关闭' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="settings.wechat_pay_enabled" class="form-item">
|
||||
<text class="label">微信商户号:</text>
|
||||
<input v-model="settings.wechat_mch_id" placeholder="请输入微信商户号" class="input-field" />
|
||||
</view>
|
||||
<view v-if="settings.wechat_pay_enabled" class="form-item">
|
||||
<text class="label">微信支付密钥:</text>
|
||||
<input v-model="settings.wechat_pay_key" type="password" placeholder="请输入微信支付密钥" class="input-field" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">支付宝支付:</text>
|
||||
<view class="switch-item">
|
||||
<switch :checked="settings.alipay_enabled" @change="onAlipayChange" />
|
||||
<text class="switch-label">{{ settings.alipay_enabled ? '已开启' : '已关闭' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="settings.alipay_enabled" class="form-item">
|
||||
<text class="label">支付宝应用ID:</text>
|
||||
<input v-model="settings.alipay_app_id" placeholder="请输入支付宝应用ID" class="input-field" />
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">余额支付:</text>
|
||||
<view class="switch-item">
|
||||
<switch :checked="settings.balance_pay_enabled" @change="onBalancePayChange" />
|
||||
<text class="switch-label">{{ settings.balance_pay_enabled ? '已开启' : '已关闭' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 物流设置 -->
|
||||
<view v-if="activeTab === 'shipping'" class="setting-section">
|
||||
<view class="section-title">物流设置</view>
|
||||
<view class="setting-form">
|
||||
<view class="form-item">
|
||||
<text class="label">默认物流公司:</text>
|
||||
<picker mode="selector" :range="expressCompanies" range-key="name" @change="onDefaultExpressChange">
|
||||
<view class="picker-text">{{ selectedExpress || '选择物流公司' }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">运费计算方式:</text>
|
||||
<picker mode="selector" :range="shippingMethods" range-key="label" @change="onShippingMethodChange">
|
||||
<view class="picker-text">{{ selectedShippingMethod || '选择计算方式' }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="label">包邮金额:</text>
|
||||
<input v-model="settings.free_shipping_amount" type="number" placeholder="请输入包邮金额" class="input-field" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 消息设置 -->
|
||||
<view v-if="activeTab === 'notification'" class="setting-section">
|
||||
<view class="section-title">消息设置</view>
|
||||
<view class="setting-form">
|
||||
<view class="form-item">
|
||||
<text class="label">短信通知:</text>
|
||||
<view class="switch-item">
|
||||
<switch :checked="settings.sms_enabled" @change="onSmsChange" />
|
||||
<text class="switch-label">{{ settings.sms_enabled ? '已开启' : '已关闭' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="settings.sms_enabled" class="form-item">
|
||||
<text class="label">短信服务商:</text>
|
||||
<picker mode="selector" :range="smsProviders" range-key="label" @change="onSmsProviderChange">
|
||||
<view class="picker-text">{{ selectedSmsProvider || '选择服务商' }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<text class="label">邮件通知:</text>
|
||||
<view class="switch-item">
|
||||
<switch :checked="settings.email_enabled" @change="onEmailChange" />
|
||||
<text class="switch-label">{{ settings.email_enabled ? '已开启' : '已关闭' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="settings.email_enabled" class="form-item">
|
||||
<text class="label">SMTP服务器:</text>
|
||||
<input v-model="settings.smtp_host" placeholder="请输入SMTP服务器" class="input-field" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<view class="save-section">
|
||||
<button class="btn btn-primary" @click="saveSettings">保存设置</button>
|
||||
<button class="btn btn-default" @click="resetSettings">重置</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
|
||||
// 响应式数据
|
||||
const activeTab = ref('basic')
|
||||
|
||||
const settingTabs = ref([
|
||||
{ key: 'basic', label: '基础设置' },
|
||||
{ key: 'payment', label: '支付设置' },
|
||||
{ key: 'shipping', label: '物流设置' },
|
||||
{ key: 'notification', label: '消息设置' }
|
||||
])
|
||||
|
||||
const settings = ref({
|
||||
// 基础设置
|
||||
site_name: '',
|
||||
site_domain: '',
|
||||
site_logo: '',
|
||||
service_phone: '',
|
||||
site_description: '',
|
||||
|
||||
// 支付设置
|
||||
wechat_pay_enabled: false,
|
||||
wechat_mch_id: '',
|
||||
wechat_pay_key: '',
|
||||
alipay_enabled: false,
|
||||
alipay_app_id: '',
|
||||
balance_pay_enabled: true,
|
||||
|
||||
// 物流设置
|
||||
default_express: '',
|
||||
shipping_method: '',
|
||||
free_shipping_amount: '',
|
||||
|
||||
// 消息设置
|
||||
sms_enabled: false,
|
||||
sms_provider: '',
|
||||
email_enabled: false,
|
||||
smtp_host: ''
|
||||
})
|
||||
|
||||
// 选项数据
|
||||
const expressCompanies = ref([])
|
||||
const shippingMethods = ref([
|
||||
{ value: 'fixed', label: '固定运费' },
|
||||
{ value: 'weight', label: '按重量计算' },
|
||||
{ value: 'pieces', label: '按件数计算' }
|
||||
])
|
||||
const smsProviders = ref([
|
||||
{ value: 'aliyun', label: '阿里云短信' },
|
||||
{ value: 'tencent', label: '腾讯云短信' },
|
||||
{ value: 'qiniu', label: '七牛云短信' }
|
||||
])
|
||||
|
||||
const selectedExpress = ref('')
|
||||
const selectedShippingMethod = ref('')
|
||||
const selectedSmsProvider = ref('')
|
||||
|
||||
// 方法
|
||||
const switchTab = (tabKey: string) => {
|
||||
activeTab.value = tabKey
|
||||
}
|
||||
|
||||
const onWechatPayChange = (e: any) => {
|
||||
settings.value.wechat_pay_enabled = e.detail.value
|
||||
}
|
||||
|
||||
const onAlipayChange = (e: any) => {
|
||||
settings.value.alipay_enabled = e.detail.value
|
||||
}
|
||||
|
||||
const onBalancePayChange = (e: any) => {
|
||||
settings.value.balance_pay_enabled = e.detail.value
|
||||
}
|
||||
|
||||
const onSmsChange = (e: any) => {
|
||||
settings.value.sms_enabled = e.detail.value
|
||||
}
|
||||
|
||||
const onEmailChange = (e: any) => {
|
||||
settings.value.email_enabled = e.detail.value
|
||||
}
|
||||
|
||||
const onDefaultExpressChange = (e: any) => {
|
||||
selectedExpress.value = expressCompanies.value[e.detail.value].name
|
||||
settings.value.default_express = expressCompanies.value[e.detail.value].code
|
||||
}
|
||||
|
||||
const onShippingMethodChange = (e: any) => {
|
||||
selectedShippingMethod.value = shippingMethods.value[e.detail.value].label
|
||||
settings.value.shipping_method = shippingMethods.value[e.detail.value].value
|
||||
}
|
||||
|
||||
const onSmsProviderChange = (e: any) => {
|
||||
selectedSmsProvider.value = smsProviders.value[e.detail.value].label
|
||||
settings.value.sms_provider = smsProviders.value[e.detail.value].value
|
||||
}
|
||||
|
||||
const chooseLogo = () => {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const tempFilePath = res.tempFilePaths[0]
|
||||
// 这里应该上传图片到服务器
|
||||
settings.value.site_logo = tempFilePath // 临时显示
|
||||
uni.showToast({
|
||||
title: '图片选择成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const saveSettings = async () => {
|
||||
try {
|
||||
await supa.from('system_settings').upsert(settings.value)
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('保存设置失败:', error)
|
||||
uni.showToast({
|
||||
title: '保存失败',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const resetSettings = () => {
|
||||
loadSettings()
|
||||
}
|
||||
|
||||
// 数据加载方法
|
||||
const loadSettings = async () => {
|
||||
try {
|
||||
const { data } = await supa.from('system_settings').select('*').single()
|
||||
if (data) {
|
||||
settings.value = { ...settings.value, ...data }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载设置失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const loadExpressCompanies = async () => {
|
||||
try {
|
||||
const { data } = await supa.from('express_companies').select('*')
|
||||
expressCompanies.value = data || []
|
||||
} catch (error) {
|
||||
console.error('加载物流公司失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 页面初始化
|
||||
onMounted(async () => {
|
||||
await Promise.all([
|
||||
loadSettings(),
|
||||
loadExpressCompanies()
|
||||
])
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.system-settings {
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
// 设置选项卡样式
|
||||
.settings-tabs {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.tab-list {
|
||||
display: flex;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
padding: 30rpx 20rpx;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 28rpx;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
&.active .tab-text {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置表单样式
|
||||
.setting-section {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #212529;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.setting-form {
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 20rpx;
|
||||
white-space: nowrap;
|
||||
min-width: 150rpx;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
height: 60rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 6rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.textarea-field {
|
||||
flex: 1;
|
||||
min-height: 120rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 6rpx;
|
||||
padding: 20rpx;
|
||||
font-size: 26rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.switch-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
|
||||
.switch-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-text {
|
||||
padding: 0 20rpx;
|
||||
height: 60rpx;
|
||||
line-height: 60rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 6rpx;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
min-width: 200rpx;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
|
||||
.logo-preview {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 8rpx;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
padding: 12rpx 24rpx;
|
||||
border: 1rpx solid #ddd;
|
||||
border-radius: 6rpx;
|
||||
background-color: #f5f5f5;
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保存按钮区域
|
||||
.save-section {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
justify-content: center;
|
||||
|
||||
.btn {
|
||||
padding: 15rpx 40rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
&.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
&.btn-default {
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 750rpx) {
|
||||
.settings-tabs {
|
||||
.tab-list {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
padding: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.form-item {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
.label {
|
||||
margin-bottom: 10rpx;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.input-field,
|
||||
.textarea-field,
|
||||
.picker-text {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.switch-item {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.save-section {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user