初始化移动端提交
This commit is contained in:
257
sheep/store/app.js
Normal file
257
sheep/store/app.js
Normal file
@@ -0,0 +1,257 @@
|
||||
import { getTenantByWebsite } from '@/sheep/api/infra/tenant';
|
||||
import { getTenantId } from '@/sheep/request';
|
||||
import { defineStore } from 'pinia';
|
||||
import $platform from '@/sheep/platform';
|
||||
import $router from '@/sheep/router';
|
||||
import user from './user';
|
||||
import sys from './sys';
|
||||
import { baseUrl, h5Url } from '@/sheep/config';
|
||||
import { themeConfig } from '@/sheep/config/theme';
|
||||
import captchaConfig from '@/sheep/config/captcha';
|
||||
|
||||
const app = defineStore({
|
||||
id: 'app',
|
||||
state: () => ({
|
||||
captchaEnable: captchaConfig.captchaEnable, // 验证码开关
|
||||
info: {
|
||||
// 应用信息
|
||||
name: '', // 商城名称
|
||||
logo: '', // logo
|
||||
version: '', // 版本号
|
||||
copyright: '', // 版权信息 I
|
||||
copytime: '', // 版权信息 II
|
||||
|
||||
cdnurl: '', // 云存储域名
|
||||
filesystem: '', // 云存储平台
|
||||
},
|
||||
platform: {
|
||||
share: {
|
||||
methods: [], // 支持的分享方式
|
||||
forwardInfo: {}, // 默认转发信息
|
||||
posterInfo: {}, // 海报信息
|
||||
linkAddress: '', // 复制链接地址
|
||||
},
|
||||
bind_mobile: 0, // 登陆后绑定手机号提醒 (弱提醒,可手动关闭)
|
||||
},
|
||||
template: {
|
||||
// 店铺装修模板
|
||||
basic: {}, // 基本信息
|
||||
home: {
|
||||
// 首页模板
|
||||
style: {},
|
||||
data: [],
|
||||
},
|
||||
user: {
|
||||
// 个人中心模板
|
||||
style: {},
|
||||
data: [],
|
||||
},
|
||||
},
|
||||
shareInfo: {}, // 全局分享信息
|
||||
has_wechat_trade_managed: 0, // 小程序发货信息管理 0 没有 || 1 有
|
||||
}),
|
||||
actions: {
|
||||
// 获取Shopro应用配置和模板
|
||||
async init(templateId = null) {
|
||||
// 检查网络
|
||||
const networkStatus = await $platform.checkNetwork();
|
||||
if (!networkStatus) {
|
||||
$router.error('NetworkError');
|
||||
}
|
||||
|
||||
// 检查配置
|
||||
if (typeof baseUrl === 'undefined') {
|
||||
$router.error('EnvError');
|
||||
}
|
||||
|
||||
// 加载租户
|
||||
await adaptTenant();
|
||||
|
||||
// 加载装修配置
|
||||
await adaptTemplate(this.template, templateId);
|
||||
|
||||
// TODO 芋艿:【初始化优化】未来支持管理后台可配;对应 https://api.shopro.sheepjs.com/shop/api/init
|
||||
if (true) {
|
||||
this.info = {
|
||||
name: '移动端',
|
||||
logo: 'https://static.iocoder.cn/ruoyi-vue-pro-logo.png',
|
||||
version: '2025.09',
|
||||
copyright: '全部开源,个人与企业可 100% 免费使用',
|
||||
copytime: 'Copyright© 2018-2025',
|
||||
|
||||
cdnurl: 'https://file.sheepjs.com', // 云存储域名
|
||||
filesystem: 'qcloud', // 云存储平台
|
||||
};
|
||||
this.platform = {
|
||||
share: {
|
||||
methods: ['forward', 'poster', 'link'],
|
||||
linkAddress: h5Url,
|
||||
posterInfo: {
|
||||
user_bg: '/static/img/shop/config/user-poster-bg.png',
|
||||
goods_bg: '/static/img/shop/config/goods-poster-bg.png',
|
||||
groupon_bg: '/static/img/shop/config/groupon-poster-bg.png',
|
||||
},
|
||||
forwardInfo: {
|
||||
title: '',
|
||||
image: '',
|
||||
desc: '',
|
||||
},
|
||||
},
|
||||
bind_mobile: 0,
|
||||
};
|
||||
this.has_wechat_trade_managed = 0;
|
||||
|
||||
// 加载主题
|
||||
const sysStore = sys();
|
||||
// 强制设置为 primary 主题,清除可能的缓存
|
||||
sysStore.setTheme('primary');
|
||||
|
||||
// 确保模板基础配置中也设置正确的主题
|
||||
if (!this.template.basic.theme || this.template.basic.theme === 'orange') {
|
||||
this.template.basic.theme = 'primary';
|
||||
}
|
||||
|
||||
// 设置默认 tabbar 配置(如果没有从 API 获取到)
|
||||
if (!this.template.basic.tabbar || !this.template.basic.tabbar.items) {
|
||||
this.template.basic.tabbar = {
|
||||
style: {
|
||||
color: '#999999',
|
||||
activeColor: themeConfig.primary.main,
|
||||
bgColor: '#ffffff',
|
||||
bgType: 'color'
|
||||
},
|
||||
mode: 1, // 使用图标模式
|
||||
items: [
|
||||
{
|
||||
text: '菜单',
|
||||
url: '/pages/index/menu',
|
||||
icon: 'sicon-goods-list',
|
||||
activeIcon: 'sicon-goods-list'
|
||||
},
|
||||
{
|
||||
text: '我的',
|
||||
url: '/pages/index/user',
|
||||
icon: 'sicon-home',
|
||||
activeIcon: 'sicon-home'
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// 模拟用户登录
|
||||
const userStore = user();
|
||||
if (userStore.isLogin) {
|
||||
userStore.loginAfter();
|
||||
}
|
||||
return Promise.resolve(true);
|
||||
} else {
|
||||
$router.error('InitError', res.msg || '加载失败');
|
||||
}
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
key: 'app-store',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
/** 初始化租户编号 */
|
||||
const adaptTenant = async () => {
|
||||
// 1. 获取当前租户 ID
|
||||
const oldTenantId = getTenantId();
|
||||
let newTenantId = null;
|
||||
|
||||
try {
|
||||
// 2.1 情况一:H5:根据 url 参数、域名来获取新的租户ID
|
||||
// #ifdef H5
|
||||
// H5 环境下的处理逻辑
|
||||
if (window?.location) {
|
||||
// 优先从 URL 查询参数获取 tenantId
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
newTenantId = urlParams.get('tenantId');
|
||||
|
||||
// 如果 URL 参数中没有,则通过 host 获取
|
||||
if (!newTenantId && window.location.host) {
|
||||
const { data } = await getTenantByWebsite(window.location.host);
|
||||
newTenantId = data?.id;
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 2.2 情况二:微信小程序:小程序环境下的处理逻辑 - 根据 appId 获取租户
|
||||
// #ifdef MP
|
||||
const appId = uni.getAccountInfoSync()?.miniProgram?.appId;
|
||||
if (appId) {
|
||||
const { data } = await getTenantByWebsite(appId);
|
||||
newTenantId = data?.id;
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 3. 如果是新租户(不相等),则进行切换
|
||||
// noinspection EqualityComparisonWithCoercionJS
|
||||
if (newTenantId && newTenantId != oldTenantId) {
|
||||
// 清理掉登录用户的 token
|
||||
const userStore = user();
|
||||
userStore.setToken();
|
||||
|
||||
// 设置新的 tenantId 到本地存储
|
||||
uni.setStorageSync('tenant-id', newTenantId);
|
||||
console.log('租户 ID 已更新:', `${oldTenantId} -> ${newTenantId}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('adaptTenant 执行失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/** 初始化装修模版 */
|
||||
const adaptTemplate = async (appTemplate, templateId) => {
|
||||
try {
|
||||
// TODO: 这里应该从真实的 API 获取模板配置
|
||||
// const { data: diyTemplate } = templateId
|
||||
// ? await DiyApi.getDiyTemplate(templateId)
|
||||
// : await DiyApi.getUsedDiyTemplate();
|
||||
|
||||
// 暂时使用默认配置
|
||||
const diyTemplate = null;
|
||||
|
||||
// 模板不存在时使用默认配置
|
||||
if (!diyTemplate) {
|
||||
console.log('使用默认装修模板配置');
|
||||
// 设置默认主题为 primary
|
||||
if (!appTemplate.basic.theme) {
|
||||
appTemplate.basic.theme = 'primary';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const tabBar = diyTemplate?.property?.tabBar;
|
||||
if (tabBar) {
|
||||
appTemplate.basic.tabbar = tabBar;
|
||||
// TODO 商城装修没有对 tabBar 进行角标配置,测试角标需打开以下注释
|
||||
// appTemplate.basic.tabbar.items.forEach((tabBar) => {
|
||||
// tabBar.dot = false
|
||||
// tabBar.badge = 100
|
||||
// })
|
||||
// appTemplate.basic.tabbar.badgeStyle = {
|
||||
// backgroundColor: '#882222',
|
||||
// }
|
||||
if (tabBar?.theme) {
|
||||
appTemplate.basic.theme = tabBar?.theme;
|
||||
}
|
||||
}
|
||||
appTemplate.home = diyTemplate?.home;
|
||||
appTemplate.user = diyTemplate?.user;
|
||||
} catch (error) {
|
||||
console.error('adaptTemplate 执行失败:', error);
|
||||
// 出错时也使用默认配置为 primary
|
||||
if (!appTemplate.basic.theme) {
|
||||
appTemplate.basic.theme = 'primary';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default app;
|
||||
66
sheep/store/company-dept.js
Normal file
66
sheep/store/company-dept.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
const defaultState = () => ({
|
||||
show: false,
|
||||
title: '请选择当前业务办理归属的公司部门信息',
|
||||
companyList: [],
|
||||
selectedCompanyId: null,
|
||||
selectedDeptId: null,
|
||||
onConfirm: null,
|
||||
onCancel: null,
|
||||
});
|
||||
|
||||
const companyDeptStore = defineStore({
|
||||
id: 'company-dept',
|
||||
state: defaultState,
|
||||
actions: {
|
||||
open({ companyList = [], onConfirm = null, onCancel = null, defaultCompanyId = null, defaultDeptId = null, title = null }) {
|
||||
this.companyList = companyList;
|
||||
this.onConfirm = onConfirm;
|
||||
this.onCancel = onCancel;
|
||||
this.title = title || '请选择当前业务办理归属的公司部门信息';
|
||||
this.show = true;
|
||||
this.selectedCompanyId = defaultCompanyId;
|
||||
this.selectedDeptId = defaultDeptId;
|
||||
if (!this.selectedCompanyId && this.companyList.length > 0) {
|
||||
this.selectedCompanyId = this.companyList[0].companyId;
|
||||
}
|
||||
if (!this.selectedDeptId) {
|
||||
const depts = this.getDeptsByCompanyId(this.selectedCompanyId);
|
||||
this.selectedDeptId = depts.length > 0 ? depts[0].deptId : null;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
Object.assign(this, defaultState());
|
||||
},
|
||||
getDeptsByCompanyId(companyId) {
|
||||
const company = this.companyList.find((item) => item.companyId === companyId);
|
||||
return company?.depts || [];
|
||||
},
|
||||
setSelectedCompany(companyId) {
|
||||
this.selectedCompanyId = companyId;
|
||||
const depts = this.getDeptsByCompanyId(companyId);
|
||||
const currentDeptIds = depts.map((dept) => dept.deptId);
|
||||
if (!currentDeptIds.includes(this.selectedDeptId)) {
|
||||
this.selectedDeptId = depts.length > 0 ? depts[0].deptId : null;
|
||||
}
|
||||
},
|
||||
setSelectedDept(deptId) {
|
||||
this.selectedDeptId = deptId;
|
||||
},
|
||||
confirm() {
|
||||
if (this.onConfirm) {
|
||||
this.onConfirm({ companyId: this.selectedCompanyId, deptId: this.selectedDeptId });
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
cancel() {
|
||||
if (this.onCancel) {
|
||||
this.onCancel();
|
||||
}
|
||||
this.close();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default companyDeptStore;
|
||||
20
sheep/store/index.js
Normal file
20
sheep/store/index.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createPinia } from 'pinia';
|
||||
import piniaPersist from 'pinia-plugin-persist-uni';
|
||||
|
||||
// 自动注入所有pinia模块
|
||||
const files = import.meta.glob('./*.js', { eager: true });
|
||||
const modules = {};
|
||||
Object.keys(files).forEach((key) => {
|
||||
modules[key.replace(/(.*\/)*([^.]+).*/gi, '$2')] = files[key].default;
|
||||
});
|
||||
|
||||
export const setupPinia = (app) => {
|
||||
const pinia = createPinia();
|
||||
pinia.use(piniaPersist);
|
||||
|
||||
app.use(pinia);
|
||||
};
|
||||
|
||||
export default (name) => {
|
||||
return modules[name]();
|
||||
};
|
||||
29
sheep/store/modal.js
Normal file
29
sheep/store/modal.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
const modal = defineStore({
|
||||
id: 'modal',
|
||||
state: () => ({
|
||||
auth: '', // 授权弹框 accountLogin|smsLogin|resetPassword|changeMobile|changePassword|changeUsername
|
||||
share: false, // 分享弹框
|
||||
menu: false, // 快捷菜单弹框
|
||||
advHistory: [], // 广告弹框记录
|
||||
lastTimer: {
|
||||
// 短信验证码计时器,为了防止刷新请求做了持久化
|
||||
smsLogin: 0,
|
||||
changeMobile: 0,
|
||||
resetPassword: 0,
|
||||
changePassword: 0,
|
||||
}
|
||||
}),
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
key: 'modal-store',
|
||||
paths: ['lastTimer', 'advHistory'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export default modal;
|
||||
32
sheep/store/sys.js
Normal file
32
sheep/store/sys.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import app from './app';
|
||||
|
||||
const sys = defineStore({
|
||||
id: 'sys',
|
||||
state: () => ({
|
||||
theme: '', // 主题,
|
||||
mode: 'light', // 明亮模式、暗黑模式(暂未支持)
|
||||
modeAuto: false, // 跟随系统
|
||||
fontSize: 1, // 设置默认字号等级(0-4)
|
||||
}),
|
||||
getters: {},
|
||||
actions: {
|
||||
setTheme(theme = '') {
|
||||
if (theme === '') {
|
||||
this.theme = app().template?.basic.theme || 'primary';
|
||||
} else {
|
||||
this.theme = theme;
|
||||
}
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
key: 'sys-store',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export default sys;
|
||||
127
sheep/store/user.js
Normal file
127
sheep/store/user.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import $share from '@/sheep/platform/share';
|
||||
import { clone, cloneDeep } from 'lodash-es';
|
||||
import app from './app';
|
||||
import UserApi from '@/sheep/api/system/user';
|
||||
import AuthUtil from '@/sheep/api/system/auth';
|
||||
import sheep from '@/sheep';
|
||||
|
||||
// 默认用户信息
|
||||
const defaultUserInfo = {
|
||||
avatar: '', // 头像
|
||||
nickname: '', // 昵称
|
||||
gender: 0, // 性别
|
||||
mobile: '', // 手机号
|
||||
};
|
||||
|
||||
// 默认钱包信息
|
||||
const defaultUserWallet = {
|
||||
balance: 0, // 余额
|
||||
};
|
||||
|
||||
const user = defineStore({
|
||||
id: 'user',
|
||||
state: () => ({
|
||||
userInfo: clone(defaultUserInfo), // 用户信息
|
||||
userWallet: clone(defaultUserWallet), // 用户钱包信息
|
||||
isLogin: !!uni.getStorageSync('token'), // 登录状态
|
||||
lastUpdateTime: 0, // 上次更新时间
|
||||
}),
|
||||
|
||||
actions: {
|
||||
// 获取用户信息
|
||||
async getInfo() {
|
||||
const { code, data } = await UserApi.getUserInfo();
|
||||
if (code !== 0) {
|
||||
return;
|
||||
}
|
||||
this.userInfo = data;
|
||||
return Promise.resolve(data);
|
||||
},
|
||||
|
||||
// 设置 token
|
||||
setToken(token = '', refreshToken = '') {
|
||||
if (token === '') {
|
||||
this.isLogin = false;
|
||||
uni.removeStorageSync('token');
|
||||
uni.removeStorageSync('refresh-token');
|
||||
} else {
|
||||
this.isLogin = true;
|
||||
uni.setStorageSync('token', token);
|
||||
uni.setStorageSync('refresh-token', refreshToken);
|
||||
this.loginAfter();
|
||||
}
|
||||
return this.isLogin;
|
||||
},
|
||||
|
||||
// 更新用户相关信息 (手动限流,5 秒之内不刷新)
|
||||
async updateUserData() {
|
||||
if (!this.isLogin) {
|
||||
this.resetUserData();
|
||||
return;
|
||||
}
|
||||
// 防抖,5 秒之内不刷新
|
||||
const nowTime = new Date().getTime();
|
||||
if (this.lastUpdateTime + 5000 > nowTime) {
|
||||
return;
|
||||
}
|
||||
this.lastUpdateTime = nowTime;
|
||||
|
||||
// 获取最新信息
|
||||
await this.getInfo();
|
||||
return this.userInfo;
|
||||
},
|
||||
|
||||
// 重置用户默认数据
|
||||
resetUserData() {
|
||||
// 清空 token
|
||||
this.setToken();
|
||||
// 清空用户相关的缓存
|
||||
this.userInfo = clone(defaultUserInfo);
|
||||
this.userWallet = clone(defaultUserWallet);
|
||||
},
|
||||
|
||||
// 登录后,加载各种信息
|
||||
async loginAfter() {
|
||||
await this.updateUserData();
|
||||
|
||||
// 登录后设置全局分享参数
|
||||
$share.getShareInfo();
|
||||
|
||||
// 提醒绑定手机号
|
||||
if (app().platform.bind_mobile && !this.userInfo.mobile) {
|
||||
sheep.$router.go('/pages/login/index', { authType: 'changeMobile' });
|
||||
}
|
||||
|
||||
// 绑定推广员
|
||||
$share.bindBrokerageUser();
|
||||
},
|
||||
|
||||
// 登出系统
|
||||
async logout(callApi = false) {
|
||||
try {
|
||||
// 如果需要调用服务器登出接口
|
||||
if (callApi && this.isLogin) {
|
||||
await AuthUtil.logout();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('调用登出接口失败:', error);
|
||||
// 即使服务器登出失败,也继续执行本地登出
|
||||
} finally {
|
||||
// 重置本地用户数据
|
||||
this.resetUserData();
|
||||
}
|
||||
return !this.isLogin;
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
key: 'user-store',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export default user;
|
||||
Reference in New Issue
Block a user