调整文件结构;跑通admin端;初步设计页面结构

This commit is contained in:
2026-01-22 18:19:15 +08:00
parent 67ef2d6d6d
commit 2b0ee0c8b6
31 changed files with 5798 additions and 198 deletions

View 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>