初始化移动端提交

This commit is contained in:
chenbowen
2025-09-30 00:08:23 +08:00
parent 08784ca8f3
commit f2ffc65094
406 changed files with 55626 additions and 93 deletions

540
pages/public/about.vue Normal file
View File

@@ -0,0 +1,540 @@
<template>
<s-layout :bgStyle="{ color: '#f5f7fa' }" class="about-page" title="关于我们">
<u-card :show-head="false" margin="20rpx" padding="40rpx" border-radius="24rpx">
<template #body>
<view class="hero-content">
<u-avatar
v-if="appInfo.logo"
:src="sheep.$url.cdn(appInfo.logo)"
size="120"
bg-color="transparent"
class="hero-logo"
/>
<u-text
:text="displayName"
type="primary"
size="40rpx"
bold
color="#fff"
class="hero-name"
/>
<u-text
:text="`${displayName} 致力于用开源的数字化能力,帮助企业快速构建电商、营销与业务协同平台。`"
size="28rpx"
color="rgba(255,255,255,0.9)"
class="hero-slogan"
/>
<view class="hero-tags">
<u-tag
v-for="tag in heroTags"
:key="tag"
:text="tag"
bg-color="rgba(255,255,255,0.16)"
color="#fff"
size="mini"
shape="circle"
plain
/>
</view>
</view>
</template>
</u-card>
<u-row gutter="16" class="metrics-row">
<u-col span="4" v-for="metric in metrics" :key="metric.title">
<u-card :show-head="false" margin="0" padding="32rpx 24rpx" border-radius="20rpx">
<template #body>
<view class="metric-content">
<u-text
:text="metric.value"
size="48rpx"
bold
type="primary"
class="metric-value"
/>
<u-text
:text="metric.title"
size="26rpx"
bold
color="#303133"
class="metric-title"
/>
<u-text
:text="metric.desc"
size="22rpx"
color="#909399"
class="metric-desc"
/>
</view>
</template>
</u-card>
</u-col>
</u-row>
<u-card :show-head="false" margin="20rpx" padding="32rpx 28rpx" border-radius="24rpx">
<template #body>
<u-text text="我们提供什么" size="32rpx" bold color="#303133" class="section-title" />
<u-text text="围绕企业全链路经营的核心能力" size="24rpx" color="#909399" class="section-subtitle" />
<view class="capability-grid">
<u-card
v-for="item in capabilities"
:key="item.title"
:show-head="false"
margin="0 0 24rpx 0"
padding="28rpx"
border-radius="20rpx"
bg-color="linear-gradient(135deg, rgba(245, 247, 250, 1), rgba(245, 247, 250, 0.6))"
>
<template #body>
<u-text :text="item.title" size="30rpx" bold color="#2c3e50" class="capability-title" />
<u-text :text="item.desc" size="24rpx" color="#606266" class="capability-desc" />
<view class="capability-tags">
<u-tag
v-for="tag in item.tags"
:key="tag"
:text="tag"
bg-color="rgba(0, 85, 162, 0.08)"
color="var(--ui-BG-Main)"
size="mini"
shape="circle"
/>
</view>
</template>
</u-card>
</view>
</template>
</u-card>
<u-card :show-head="false" margin="20rpx" padding="32rpx 28rpx" border-radius="24rpx">
<template #body>
<u-text text="我们的理念" size="32rpx" bold color="#303133" class="section-title" />
<view class="value-list">
<u-card
v-for="item in values"
:key="item.title"
:show-head="false"
margin="0 0 24rpx 0"
padding="24rpx 26rpx"
border-radius="20rpx"
bg-color="rgba(0, 85, 162, 0.05)"
>
<template #body>
<u-text :text="item.title" size="28rpx" bold color="#2c3e50" class="value-title" />
<u-text :text="item.desc" size="24rpx" color="#606266" class="value-desc" />
</template>
</u-card>
</view>
</template>
</u-card>
<u-card :show-head="false" margin="20rpx" padding="32rpx 28rpx" border-radius="24rpx">
<template #body>
<u-text text="发展里程碑" size="32rpx" bold color="#303133" class="section-title" />
<view class="timeline">
<view
class="timeline-item"
v-for="(item, index) in milestones"
:key="item.year"
>
<view class="timeline-dot"></view>
<view class="timeline-content">
<u-text :text="item.year" size="28rpx" bold color="#2c3e50" class="timeline-year" />
<u-text :text="item.title" size="26rpx" bold color="#303133" class="timeline-title" />
<u-text :text="item.desc" size="24rpx" color="#606266" class="timeline-desc" />
</view>
</view>
</view>
</template>
</u-card>
<u-card :show-head="false" margin="20rpx" padding="32rpx 28rpx" border-radius="24rpx">
<template #body>
<u-text text="联系与合作" size="32rpx" bold color="#303133" class="section-title" />
<u-text text="欢迎与我们探讨更多共赢的可能" size="24rpx" color="#909399" class="section-subtitle" />
<view class="contact-list">
<u-cell
v-for="item in contacts"
:key="item.label"
:title="item.label"
:label="item.value"
:is-link="true"
arrow-direction="right"
bg-color="rgba(245, 247, 250, 0.8)"
title-style="font-size: 26rpx; font-weight: 600; color: #2c3e50;"
label-style="font-size: 24rpx; color: #606266; word-break: break-all; line-height: 34rpx;"
@click="handleContact(item)"
class="contact-cell"
/>
</view>
</template>
</u-card>
<u-text
text="移动商城 始终坚持开源共享,与开发者和企业伙伴一起打造可持续的数字化生态。"
size="24rpx"
color="#909399"
align="center"
class="footer-hint"
/>
</s-layout>
</template>
<script setup>
import { computed } from 'vue';
import sheep from '@/sheep';
const appInfo = computed(() => sheep.$store('app').info || {});
const displayName = computed(() => appInfo.value.name || '移动商城');
const heroTags = [
'100% 开源可商用',
'支持多端统一交付',
'沉淀企业级最佳实践'
];
const metrics = [
{
title: '开源历程',
value: '7+',
desc: '年持续迭代与社区共建'
},
{
title: '行业方案',
value: '20+',
desc: '覆盖零售、制造、政企等场景'
},
{
title: '交付效率',
value: '30%',
desc: '平均缩短客户上线周期'
}
];
const capabilities = [
{
title: '产品矩阵',
desc: '以电商中台为核心,延展直播带货、会员营销、全渠道订单与履约管理。',
tags: ['商城交易', '营销裂变', '数据运营']
},
{
title: '技术架构',
desc: '基于 Spring Cloud Alibaba + Vue3 + UniApp支持多租户、微服务与多端同源。',
tags: ['微服务', '多端一致', '低代码装修']
},
{
title: '服务体系',
desc: '提供从咨询、定制、交付到长期运营的全生命周期陪伴式服务。',
tags: ['数字化顾问', '驻场交付', '持续运营']
}
];
const values = [
{
title: '使命',
desc: '让每一家企业都能以更低成本、更快速度完成业务数字化升级。'
},
{
title: '愿景',
desc: '打造开放、可信赖、可持续的企业级数字商业生态。'
},
{
title: '价值观',
desc: '客户成功、极致体验、持续创新、坦诚协作。'
}
];
const milestones = [
{
year: '2018',
title: '开源起航',
desc: '发布首个电商项目原型,与社区开发者共同启动开源计划。'
},
{
year: '2020',
title: '企业级升级',
desc: '引入多租户、权限与大促能力,满足成长型企业核心诉求。'
},
{
year: '2022',
title: '多端一体',
desc: '统一 H5、App 与小程序技术栈,实现一次开发,多端交付。'
},
{
year: '2024',
title: '智能加速',
desc: '引入智能客服、营销推荐等 AI 能力,提升运营效率。'
},
{
year: '2025',
title: '生态共建',
desc: '联合生态伙伴共建行业方案,形成开放合作的生态体系。'
}
];
const contacts = [
{
label: '商务合作',
value: 'business@iocoder.cn',
type: 'email'
},
{
label: '客服热线',
value: '400-860-888',
type: 'phone',
actionValue: '400860888'
},
{
label: '开源仓库',
value: 'https://github.com/YunaiV/ruoyi-vue-pro',
type: 'link'
},
{
label: '文档中心',
value: 'https://doc.iocoder.cn',
type: 'link'
},
{
label: '办公地址',
value: '浙江省杭州市滨江区江南大道 777 号数字产业园',
type: 'text'
}
];
function handleContact(item) {
if (item.type === 'phone') {
const phoneNumber = item.actionValue || item.value.replace(/[^0-9]/g, '');
if (!phoneNumber) {
return;
}
uni.makePhoneCall({
phoneNumber,
fail: () => {
uni.setClipboardData({
data: item.value,
success: () => {
uni.showToast({ title: '号码已复制', icon: 'none' });
}
});
}
});
return;
}
if (item.type === 'link') {
sheep.$router.go('/pages/public/webview', {
title: item.label,
url: encodeURIComponent(item.value)
});
uni.setClipboardData({
data: item.value,
success: () => {
uni.showToast({ title: '链接已复制', icon: 'none' });
}
});
return;
}
if (item.type === 'text') {
uni.setClipboardData({
data: item.value,
success: () => {
uni.showToast({ title: '地址已复制', icon: 'none' });
}
});
return;
}
uni.setClipboardData({
data: item.value,
success: () => {
uni.showToast({ title: '信息已复制', icon: 'none' });
}
});
}
</script>
<style lang="scss" scoped>
.about-page {
min-height: 100vh;
padding: 0;
background: #f5f7fa;
box-sizing: border-box;
}
// Hero card 渐变背景
:deep(.u-card) {
&:first-child {
background: linear-gradient(135deg, rgba(0, 85, 162, 0.95), rgba(0, 85, 162, 0.68));
box-shadow: 0 16rpx 36rpx rgba(0, 85, 162, 0.25);
color: #fff;
}
}
.hero-content {
display: flex;
flex-direction: column;
align-items: flex-start;
text-align: left;
.hero-logo {
margin-bottom: 24rpx;
border-radius: 24rpx;
background: rgba(255, 255, 255, 0.15);
padding: 16rpx;
}
.hero-name {
margin-bottom: 16rpx;
}
.hero-slogan {
margin-bottom: 28rpx;
line-height: 42rpx;
}
.hero-tags {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
}
.metrics-row {
margin: 20rpx;
}
.metric-content {
display: flex;
flex-direction: column;
align-items: flex-start;
text-align: left;
.metric-value {
margin-bottom: 8rpx;
}
.metric-title {
margin-bottom: 6rpx;
}
.metric-desc {
line-height: 32rpx;
}
}
.section-title {
margin-bottom: 12rpx;
}
.section-subtitle {
margin-bottom: 24rpx;
}
.capability-grid {
display: flex;
flex-direction: column;
}
.capability-title {
margin-bottom: 12rpx;
}
.capability-desc {
margin-bottom: 16rpx;
line-height: 38rpx;
}
.capability-tags {
display: flex;
flex-wrap: wrap;
gap: 14rpx;
}
.value-list {
display: flex;
flex-direction: column;
}
.value-title {
margin-bottom: 12rpx;
}
.value-desc {
line-height: 36rpx;
}
.timeline {
position: relative;
margin-left: 20rpx;
padding-left: 20rpx;
border-left: 2rpx solid rgba(0, 85, 162, 0.2);
display: flex;
flex-direction: column;
gap: 32rpx;
.timeline-item {
position: relative;
.timeline-dot {
position: absolute;
left: -31rpx;
top: 6rpx;
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background: var(--ui-BG-Main);
box-shadow: 0 0 0 6rpx rgba(0, 85, 162, 0.15);
}
.timeline-content {
padding-left: 12rpx;
.timeline-year {
margin-bottom: 6rpx;
}
.timeline-title {
margin-bottom: 6rpx;
}
.timeline-desc {
line-height: 36rpx;
}
}
}
}
.contact-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.contact-cell {
border-radius: 18rpx;
overflow: hidden;
}
.footer-hint {
padding: 24rpx 36rpx 80rpx;
line-height: 36rpx;
}
@media (min-width: 750px) {
.metrics-row {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.capability-grid,
.value-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24rpx;
}
}
</style>

60
pages/public/error.vue Normal file
View File

@@ -0,0 +1,60 @@
<!-- 错误界面 -->
<template>
<view class="error-page">
<s-empty
v-if="errCode === 'NetworkError'"
icon="/static/internet-empty.png"
text="网络连接失败"
showAction
actionText="重新连接"
@clickAction="onReconnect"
buttonColor="#ff3000"
/>
<s-empty
v-else-if="errCode === 'TemplateError'"
icon="/static/internet-empty.png"
text="未找到模板,请前往后台启用对应模板"
showAction
actionText="重新加载"
@clickAction="onReconnect"
buttonColor="#ff3000"
/>
<s-empty
v-else-if="errCode !== ''"
icon="/static/internet-empty.png"
:text="errMsg"
showAction
actionText="重新加载"
@clickAction="onReconnect"
buttonColor="#ff3000"
/>
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
import { ShoproInit } from '@/sheep';
const errCode = ref('');
const errMsg = ref('');
onLoad((options) => {
errCode.value = options.errCode;
errMsg.value = options.errMsg;
});
// 重新连接
async function onReconnect() {
uni.reLaunch({
url: '/pages/index/menu',
});
await ShoproInit();
}
</script>
<style lang="scss" scoped>
.error-page {
width: 100%;
}
</style>

15
pages/public/faq.vue Normal file
View File

@@ -0,0 +1,15 @@
<!-- 页面已移除 -->
<template>
<s-layout :bgStyle="{ color: '#FFF' }" class="set-wrap" title="页面已下线">
<s-empty text="该页面已下线" icon="/static/internet-empty.png" />
</s-layout>
</template>
<script setup>
</script>
<style lang="scss" scoped>
.set-wrap {
min-height: 100vh;
}
</style>

45
pages/public/richtext.vue Normal file
View File

@@ -0,0 +1,45 @@
<!-- 文章展示 -->
<template>
<s-layout :bgStyle="{ color: '#FFF' }" :title="state.title" class="set-wrap">
<view class="ss-p-30 richtext"><mp-html :content="state.content"></mp-html></view>
</s-layout>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { reactive } from 'vue';
// Article API removed with promotion module
const state = reactive({
title: '',
content: '',
});
async function getRichTextContent(id, title) {
// Article API has been removed as it was part of promotion module
state.title = title || '内容';
state.content = '暂无内容';
}
onLoad((options) => {
if (options.title) {
state.title = options.title;
uni.setNavigationBarTitle({
title: state.title,
});
}
getRichTextContent(options.id, options.title);
});
</script>
<style lang="scss" scoped>
.set-title {
margin: 0 30rpx;
}
:deep() {
image {
display: block;
}
}
</style>

236
pages/public/setting.vue Normal file
View File

@@ -0,0 +1,236 @@
<template>
<s-layout :bgStyle="{ color: '#fff' }" class="set-wrap" title="系统设置">
<view class="header-box ss-flex-col ss-row-center ss-col-center">
<image
class="logo-img ss-m-b-46"
:src="sheep.$url.cdn(appInfo.logo)"
mode="aspectFit"
></image>
<view class="name ss-m-b-24">{{ appInfo.name }}</view>
</view>
<view class="container-list">
<uni-list :border="false">
<uni-list-item
title="当前版本"
:rightText="appInfo.version"
showArrow
clickable
:border="false"
class="list-border"
@tap="onCheckUpdate"
/>
<uni-list-item
title="本地缓存"
:rightText="storageSize"
showArrow
:border="false"
class="list-border"
/>
<uni-list-item
title="关于我们"
showArrow
clickable
:border="false"
class="list-border"
@tap="
sheep.$router.go('/pages/public/richtext', {
title: '关于我们'
})
"
/>
<!-- 为了过审 只有 iOS-App 有注销账号功能 -->
<uni-list-item
v-if="isLogin && sheep.$platform.os === 'ios' && sheep.$platform.name === 'App'"
title="注销账号"
rightText=""
showArrow
clickable
:border="false"
class="list-border"
@click="onLogoff"
/>
</uni-list>
</view>
<view class="set-footer ss-flex-col ss-row-center ss-col-center">
<view class="agreement-box ss-flex ss-col-center ss-m-b-40">
<view class="ss-flex ss-col-center ss-m-b-10">
<view
class="tcp-text"
@tap="
sheep.$router.go('/pages/public/richtext', {
title: '用户协议'
})
"
>
用户协议
</view>
<view class="agreement-text"></view>
<view
class="tcp-text"
@tap="
sheep.$router.go('/pages/public/richtext', {
title: '隐私协议'
})
"
>
隐私协议
</view>
</view>
</view>
<view class="copyright-text ss-m-b-10">{{ appInfo.copyright }}</view>
<view class="copyright-text">{{ appInfo.copytime }}</view>
</view>
<su-fixed bottom placeholder>
<view class="ss-p-x-20 ss-p-b-40">
<button
class="loginout-btn ss-reset-button ui-BG-Main ui-Shadow-Main"
@tap="onLogout"
v-if="isLogin"
>
退出登录
</button>
</view>
</su-fixed>
</s-layout>
</template>
<script setup>
import sheep from '@/sheep';
import { computed, reactive } from 'vue';
import AuthUtil from '@/sheep/api/system/auth';
const appInfo = computed(() => sheep.$store('app').info);
const isLogin = computed(() => sheep.$store('user').isLogin);
const storageSize = uni.getStorageInfoSync().currentSize + 'Kb';
const state = reactive({
showModal: false,
});
function onCheckUpdate() {
sheep.$platform.checkUpdate();
// 小程序初始化时已检查更新
// H5实时更新无需检查
// App 1.跳转应用市场更新 2.手动热更新 3.整包更新
}
// 注销账号
function onLogoff() {
uni.showModal({
title: '提示',
content: '确认注销账号?',
success: async function (res) {
if (!res.confirm) {
return;
}
const { code } = await AuthUtil.logout();
if (code !== 0) {
return;
}
sheep.$store('user').logout();
sheep.$router.go('/pages/index/user');
},
});
}
// 退出账号
function onLogout() {
uni.showModal({
title: '提示',
content: '确认退出账号?',
success: async function (res) {
if (!res.confirm) {
return;
}
const { code } = await AuthUtil.logout();
if (code !== 0) {
return;
}
sheep.$store('user').logout();
sheep.$router.go('/pages/index/user');
},
});
}
</script>
<style lang="scss" scoped>
.container-list {
width: 100%;
}
.set-title {
margin: 0 30rpx;
}
.header-box {
padding: 100rpx 0;
.logo-img {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
}
.name {
font-size: 42rpx;
font-weight: 400;
color: $dark-3;
}
.version {
font-size: 32rpx;
font-weight: 500;
line-height: 32rpx;
color: $gray-b;
}
}
.set-footer {
margin: 100rpx 0 0 0;
.copyright-text {
font-size: 22rpx;
font-weight: 500;
color: $gray-c;
line-height: 30rpx;
}
.agreement-box {
font-size: 26rpx;
font-weight: 500;
.tcp-text {
color: var(--ui-BG-Main);
}
.agreement-text {
color: $dark-9;
}
}
}
.loginout-btn {
width: 100%;
height: 80rpx;
border-radius: 40rpx;
font-size: 30rpx;
}
.list-border {
font-size: 28rpx;
font-weight: 400;
color: #333333;
border-bottom: 2rpx solid #eeeeee;
}
:deep(.uni-list-item__content-title) {
font-size: 28rpx;
font-weight: 500;
color: #333;
}
:deep(.uni-list-item__extra-text) {
color: #bbbbbb;
font-size: 28rpx;
}
</style>

18
pages/public/webview.vue Normal file
View File

@@ -0,0 +1,18 @@
<!-- 网页加载 -->
<template>
<view>
<web-view :src="url" />
</view>
</template>
<script setup>
import { onLoad } from '@dcloudio/uni-app';
import { ref } from 'vue';
const url = ref('');
onLoad((options) => {
url.value = decodeURIComponent(options.url);
});
</script>
<style lang="scss" scoped></style>