初始化
This commit is contained in:
217
utils/common.ts
Normal file
217
utils/common.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import type {Company} from "~/api/system/company/model";
|
||||
const route = useRoute();
|
||||
|
||||
/**需要进行持久化的数据:把需要持久化的数据放在下面这个对象中,才会持久化,不需要持久化的数据就不用放到这里了。 */
|
||||
const enduring: { [key: string]: () => Ref<any> } = {
|
||||
useToken, useConfigInfo
|
||||
}
|
||||
|
||||
//下面的俩函数在app.vue的onMounted中统一调用,或者在其它情况挂载后单独调用。
|
||||
/**把所有指定数据保存到本地存储
|
||||
* @param key 要保存的数据名。不填的话就是保存全部(一般不填,统一在页面关闭时保存。如果是特别重要的数据,就时不时单独保存一下即可。)
|
||||
*/
|
||||
export const setLocal = (key?: string) => {
|
||||
if (key) {
|
||||
console.log('只保存', key);
|
||||
const useKey = 'use' + key.slice(0, 1).toUpperCase() + key.slice(1).toLowerCase(); //首字母大写,其它全部转小写
|
||||
const func = enduring[useKey];
|
||||
if (!func) {
|
||||
console.log('没有找到', useKey, '对应的函数');
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(key, JSON.stringify(func().value));
|
||||
} else {
|
||||
console.log('正在保存全部数据');
|
||||
for (const key in enduring) {
|
||||
if (Object.prototype.hasOwnProperty.call(enduring, key)) {
|
||||
const element = enduring[key];
|
||||
const setKey = key.toLowerCase().substring(3); //去掉前面的use ,其它全部转小写
|
||||
try {
|
||||
localStorage.setItem(setKey, JSON.stringify(element().value));
|
||||
} catch (error) {
|
||||
console.log(`在设置${setKey}的数据时出现错误`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
/**从本地存储获取数据到state中 */
|
||||
export const getLoacl = () => {
|
||||
for (const key in enduring) {
|
||||
if (Object.prototype.hasOwnProperty.call(enduring, key)) {
|
||||
const element = enduring[key];
|
||||
const setKey = key.toLowerCase().substring(3); //去掉前面的use ,其它全部转小写
|
||||
try {
|
||||
const localData = localStorage.getItem(setKey) || '';
|
||||
if (localData) {
|
||||
element().value = JSON.parse(localData);
|
||||
console.log(setKey, '的本地存储数据获取成功', element().value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(`在获取${setKey}的数据时出现错误`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断是否为整数
|
||||
* @param num
|
||||
*/
|
||||
export const isInteger = (num: any) => {
|
||||
return /^-?\d+$/.test(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取传参中的ID
|
||||
* param 12334.html
|
||||
* return 1234
|
||||
* @param num
|
||||
*/
|
||||
export const getIdByParam = () => {
|
||||
const split = String(route.params.id).split('.')
|
||||
return split[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取传参中的ID
|
||||
* param 12334.html
|
||||
* return 1234
|
||||
* @param num
|
||||
*/
|
||||
export const getIdBySpm = (index: number) => {
|
||||
console.log('split',route.query)
|
||||
const split = String(route.query.spm).split('.')
|
||||
return split[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前网址的Path部分
|
||||
*/
|
||||
export const getPath = () => {
|
||||
return route.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转页面函数
|
||||
* 携带用于统计用户行为的参数
|
||||
* @param path /product/detail.html
|
||||
* @param id 128
|
||||
* @param d 项目数据
|
||||
* @param isOpen 是否新窗口打开
|
||||
* @param isToken 是否登录控制台
|
||||
* 拼接规则: {域名}{path}?spm=c.{用户ID}.{租户ID}.{栏目ID}.{商品ID}.{timestamp}&token={token}
|
||||
* @return https:///websoft.top/product/detail/128.html?spm=c.5.3057.10005.undefined&token=DDkr1PpE9DouIVMjLEMt9733QsgG7oNV
|
||||
*/
|
||||
export function openSpmUrl(p: string, d?: any, id = 0, isOpen?: boolean, isToken?: boolean): void {
|
||||
const config = useWebsite();
|
||||
const itemId = ref<number>(0);
|
||||
const path = ref<string>('');
|
||||
const spm = ref<string>('');
|
||||
const model = ref<string>('c');
|
||||
const tid = d?.tenantId || localStorage.getItem('TID_ADMIN');
|
||||
const mid = config.value.loginUser?.merchantId || 0;
|
||||
const pid = d?.parentId || 0;
|
||||
const cid = d?.categoryId || 0;
|
||||
const uid = localStorage.getItem('UserId') || 0;
|
||||
const timestamp = ref(Date.now() / 1000);
|
||||
let token = '';
|
||||
|
||||
// TODO 登录控制台
|
||||
if(isToken){
|
||||
token = `&token=${localStorage.getItem('token')}`;
|
||||
}
|
||||
// TODO 判断模型
|
||||
if(d?.articleId){
|
||||
model.value = 'a';
|
||||
}
|
||||
if(d?.goodsId){
|
||||
model.value = 'g';
|
||||
}
|
||||
if(d?.productId){
|
||||
model.value = 'p';
|
||||
}
|
||||
if(d?.appId){
|
||||
model.value = 'app';
|
||||
}
|
||||
if(d?.plugId){
|
||||
model.value = 'plug';
|
||||
}
|
||||
if(d?.itemId > 0){
|
||||
path.value = d.path;
|
||||
itemId.value = d.itemId;
|
||||
}else {
|
||||
path.value = p;
|
||||
itemId.value = id;
|
||||
}
|
||||
if(d?.model === 'links'){
|
||||
window.open(d.path,'_blank');
|
||||
return;
|
||||
}
|
||||
// TODO 封装spm
|
||||
spm.value = `?spm=${model.value}.${tid}.${mid}.${pid}.${cid}.${itemId.value}.${uid}.${timestamp.value}${token}`;
|
||||
|
||||
// TODO 账号密码
|
||||
if(d?.account || d?.password){
|
||||
spm.value += `&account=${d.account}&password=${d.password}`;
|
||||
}
|
||||
|
||||
// TODO 新窗口打开
|
||||
if(isOpen){
|
||||
window.open(`${path.value}${spm.value}`,'_blank');
|
||||
return;
|
||||
}else {
|
||||
window.open(`${path.value}${spm.value}`, '_top');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 单点登录控制台
|
||||
export function loginAdminByToken(): void {
|
||||
const user = useUser();
|
||||
const uid = user.value?.userId;
|
||||
const tid = user.value?.tenantId;
|
||||
openSpmUrl(`https://console.websoft.top/token-login`,undefined, uid, true,true)
|
||||
}
|
||||
|
||||
|
||||
// 单点登录开发者中心
|
||||
export function loginDeveloperCenterByToken(item: Company): void {
|
||||
const user = useUser();
|
||||
const tenantId = Number(user.value?.tenantId);
|
||||
const token = localStorage.getItem('token');
|
||||
if(!token){
|
||||
window.open(`https://${item.domain}`, '_blank')
|
||||
return;
|
||||
}
|
||||
openSpmUrl(`https://${item.domain}/token-login`,undefined, tenantId, true,true)
|
||||
}
|
||||
|
||||
// 单点登录应用控制台
|
||||
export function loginByToken(item: Company): void {
|
||||
const user = useUser();
|
||||
const tenantId = Number(user.value?.tenantId);
|
||||
const token = localStorage.getItem('token');
|
||||
window.open(`https://${item.domain}`, '_blank')
|
||||
}
|
||||
|
||||
export function getSpmUrl(path: string, d?: any, id = 0): string {
|
||||
const config = useWebsite();
|
||||
const spm = ref<string>('');
|
||||
const model = ref<string>('c');
|
||||
const tid = config.value.tenantId || 0;
|
||||
const mid = config.value.loginUser?.merchantId || 0;
|
||||
const pid = d?.parentId || 0;
|
||||
const cid = d?.categoryId || 0;
|
||||
const uid = config.value.loginUser?.userId || 0;
|
||||
const timestamp = ref(Date.now() / 1000);
|
||||
let token = uuidv4();
|
||||
// TODO 封装spm
|
||||
spm.value = `?spm=${model.value}.${tid}.${mid}.${pid}.${cid}.${id}.${uid}.${timestamp.value}&token=${token}`;
|
||||
return `${path}${spm.value}`
|
||||
}
|
||||
|
||||
export function openUrl(url: string) {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
104
utils/domain.ts
Normal file
104
utils/domain.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
// 解析域名结构
|
||||
export function getHost(): any {
|
||||
const host = window.location.host;
|
||||
return host.split('.');
|
||||
}
|
||||
|
||||
// 是否https
|
||||
export function isHttps() {
|
||||
const protocol = window.location.protocol;
|
||||
if (protocol == 'https:') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取原始域名
|
||||
* @return http://www.domain.com
|
||||
*/
|
||||
export function getOriginDomain(): string {
|
||||
return window.origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 域名的第一部分
|
||||
* 获取tenantId
|
||||
* @return 10140
|
||||
*/
|
||||
export function getDomainPart1(): any {
|
||||
const split = getHost();
|
||||
if (split[0] == '127') {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof (split[0])) {
|
||||
return split[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过解析泛域名获取租户ID
|
||||
* https://10140.wsdns.cn
|
||||
* @return 10140
|
||||
*/
|
||||
export function getTenantId() {
|
||||
return getDomainPart1();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根域名
|
||||
* hostname
|
||||
*/
|
||||
export function getHostname(): string {
|
||||
return window.location.hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取域名
|
||||
* @return https://www.domain.com
|
||||
*/
|
||||
export function getDomain(): string {
|
||||
return window.location.protocol + '//www.' + getRootDomain();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取根域名
|
||||
* abc.com
|
||||
*/
|
||||
export function getRootDomain(): string {
|
||||
const split = getHost();
|
||||
return split[split.length - 2] + '.' + split[split.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二级域名
|
||||
* @return abc.com
|
||||
*/
|
||||
export function getSubDomainPath(): string {
|
||||
const split = getHost();
|
||||
if (split.length == 2) {
|
||||
return '';
|
||||
}
|
||||
return split[split.length - 3];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取产品标识
|
||||
* @return 10048
|
||||
*/
|
||||
export function getProductCode(): string | null {
|
||||
const subDomain = getSubDomainPath();
|
||||
if (subDomain == undefined) {
|
||||
return null;
|
||||
}
|
||||
const split = subDomain.split('-');
|
||||
return split[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制台域名
|
||||
*/
|
||||
export function navSubDomain(path: string): string {
|
||||
return `${window.location.protocol}//${path}.${getRootDomain()}`;
|
||||
}
|
||||
68
utils/loadScript.ts
Normal file
68
utils/loadScript.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
const callbacks: any = {};
|
||||
|
||||
/**
|
||||
* 加载一个远程脚本
|
||||
* @param {String} src 一个远程脚本
|
||||
* @param {Function} callback 回调
|
||||
*/
|
||||
function loadScript(src: string, callback: { (): void; (): void }) {
|
||||
const existingScript = document.getElementById(src);
|
||||
const cb = callback || (() => {});
|
||||
if (!existingScript) {
|
||||
callbacks[src] = [];
|
||||
const $script: HTMLScriptElement = document.createElement('script');
|
||||
$script.src = src;
|
||||
$script.id = src;
|
||||
$script.async = Boolean(1);
|
||||
document.body.appendChild($script);
|
||||
const onEnd = 'onload' in $script ? stdOnEnd.bind($script) : ieOnEnd.bind($script);
|
||||
// @ts-ignore
|
||||
onEnd($script);
|
||||
}
|
||||
|
||||
callbacks[src].push(cb);
|
||||
|
||||
function stdOnEnd(script: { onload?: () => void; onerror: () => void }) {
|
||||
script.onload = () => {
|
||||
// @ts-ignore
|
||||
this.onerror = this.onload = null;
|
||||
callbacks[src].forEach(
|
||||
(item: (arg0: null, arg1: { onload?: (() => void) | undefined; onerror: () => void }) => void) => {
|
||||
item(null, script);
|
||||
}
|
||||
);
|
||||
delete callbacks[src];
|
||||
};
|
||||
script.onerror = () => {
|
||||
// @ts-ignore
|
||||
this.onerror = this.onload = null;
|
||||
// @ts-ignore
|
||||
cb(new Error(`Failed to load ${src}`), script);
|
||||
};
|
||||
}
|
||||
|
||||
function ieOnEnd(script: { onreadystatechange: () => void }) {
|
||||
script.onreadystatechange = () => {
|
||||
// @ts-ignore
|
||||
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return;
|
||||
// @ts-ignore
|
||||
this.onreadystatechange = null;
|
||||
callbacks[src].forEach((item: (arg0: null, arg1: { onreadystatechange: () => void }) => void) => {
|
||||
item(null, script);
|
||||
});
|
||||
delete callbacks[src];
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 顺序加载一组远程脚本
|
||||
* @param {Array} list 一组远程脚本
|
||||
* @param {Function} cb 回调
|
||||
*/
|
||||
export function loadScriptQueue(list: any[], cb: { (): void; (): void }) {
|
||||
const first = list.shift();
|
||||
list.length ? loadScript(first, () => loadScriptQueue(list, cb)) : loadScript(first, cb);
|
||||
}
|
||||
|
||||
export default loadScript;
|
||||
88
utils/request.ts
Normal file
88
utils/request.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* axios 实例
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import type { AxiosResponse } from 'axios';
|
||||
import {API_BASE_URL, TOKEN_HEADER_NAME, LAYOUT_PATH, TOKEN_STORE_NAME} from '@/config';
|
||||
import type { ApiResult } from '@/api';
|
||||
import { getHostname, getTenantId } from '@/utils/domain';
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: API_BASE_URL
|
||||
});
|
||||
|
||||
/**
|
||||
* 添加请求拦截器
|
||||
*/
|
||||
service.interceptors.request.use(
|
||||
(config) => {
|
||||
const TENANT_ID = localStorage.getItem('TenantId') || 5;
|
||||
const token = localStorage.getItem(TOKEN_STORE_NAME);
|
||||
// 添加 token 到 header
|
||||
if (token && config.headers) {
|
||||
config.headers.common[TOKEN_HEADER_NAME] = token;
|
||||
}
|
||||
// 获取租户ID
|
||||
if (config.headers) {
|
||||
// 附加企业ID
|
||||
const companyId = localStorage.getItem('CompanyId');
|
||||
if (companyId) {
|
||||
config.headers.common['CompanyId'] = companyId;
|
||||
}
|
||||
// 通过网站域名获取租户ID
|
||||
if (getHostname()) {
|
||||
config.headers.common['Domain'] = getHostname();
|
||||
}
|
||||
// 解析二级域名获取租户ID
|
||||
if (getTenantId()) {
|
||||
config.headers.common['TenantId'] = getTenantId();
|
||||
return config;
|
||||
}
|
||||
if (TENANT_ID) {
|
||||
config.headers.common['TenantId'] = TENANT_ID;
|
||||
return config;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 添加响应拦截器
|
||||
*/
|
||||
service.interceptors.response.use(
|
||||
(res: AxiosResponse<ApiResult<unknown>>) => {
|
||||
// 登录过期处理
|
||||
if (res.data?.code === 401) {
|
||||
// const currentPath = unref(router.currentRoute).path;
|
||||
// if (currentPath == LAYOUT_PATH) {
|
||||
// logout(true);
|
||||
// } else {
|
||||
// Modal.destroyAll();
|
||||
// Modal.info({
|
||||
// title: '系统提示',
|
||||
// content: '登录状态已过期, 请退出重新登录!',
|
||||
// okText: '重新登录',
|
||||
// onOk: () => {
|
||||
// logout(false, currentPath);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// return Promise.reject(new Error(res.data.message));
|
||||
}
|
||||
// token 自动续期
|
||||
const token = res.headers[TOKEN_HEADER_NAME.toLowerCase()];
|
||||
if (token) {
|
||||
localStorage.setItem(TOKEN_STORE_NAME, token);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default service;
|
||||
25
utils/tool.ts
Normal file
25
utils/tool.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export function escapeHtml(str: string) {
|
||||
let temp = '';
|
||||
if (str.length === 0) return '';
|
||||
temp = str.replace(/&/g, '&');
|
||||
temp = temp.replace(/</g, '<');
|
||||
temp = temp.replace(/>/g, '>');
|
||||
temp = temp.replace(/ /g, ' ');
|
||||
temp = temp.replace(/'/g, "'");
|
||||
temp = temp.replace(/"/g, '"');
|
||||
return temp;
|
||||
}
|
||||
|
||||
export function isArray(str: unknown) {
|
||||
return Object.prototype.toString.call(str) === '[object Array]';
|
||||
}
|
||||
|
||||
// 配置服务器接口
|
||||
export function getBaseUrl() {
|
||||
console.log('process:',process.server)
|
||||
if (process.server) {
|
||||
return "https://modules.gxwebsoft.com/api"
|
||||
} else {
|
||||
return "https://modules.gxwebsoft.com/api"
|
||||
}
|
||||
}
|
||||
29
utils/use-form-data.ts
Normal file
29
utils/use-form-data.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { reactive } from 'vue';
|
||||
|
||||
/**
|
||||
* 表单数据 hook
|
||||
* @param initValue 默认值
|
||||
*/
|
||||
export default function <T extends object>(initValue?: T) {
|
||||
const form = reactive<T>({ ...initValue } as T);
|
||||
|
||||
const resetFields = () => {
|
||||
Object.keys(form).forEach((key) => {
|
||||
form[key] = initValue ? initValue[key] : void 0;
|
||||
});
|
||||
};
|
||||
|
||||
const assignFields = (data: object) => {
|
||||
Object.keys(form).forEach((key) => {
|
||||
form[key] = data[key];
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
form,
|
||||
// 重置为初始值
|
||||
resetFields,
|
||||
// 赋值不改变字段
|
||||
assignFields
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user