Commit 1d34a98e authored by wangjiankun's avatar wangjiankun

init: 项目

parent 5b7b2ef5
# Editor configuration, see http://editorconfig.org
# 表示是最顶层的 EditorConfig 配置文件
root = true
[*] # 表示所有文件适用
charset = utf-8 # 设置文件字符集为 utf-8
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = lf # 控制换行类型(lf | cr | crlf)
trim_trailing_whitespace = true # 去除行首的任意空白字符
insert_final_newline = true # 始终在文件末尾插入一个新行
[*.md] # 表示仅 md 文件适用以下规则
max_line_length = off
trim_trailing_whitespace = false
# 以下变量在`development`被载入
VITE_APP_BASE_API = '/qy-api'
VITE_APP_WX_URL = '/wx'
# 以下变量在`production`被载入
VITE_APP_BASE_API = 'http://117.122.212.102:8092/qy-api/'
VITE_APP_WX_URL = 'https://open.weixin.qq.com'
\ No newline at end of file
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'plugin:vue/essential',
'airbnb-base',
],
globals: {
youngDanStorage: 'writable',
},
parserOptions: {
ecmaVersion: 13,
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
plugins: [
'vue',
'@typescript-eslint',
],
rules: {
// 下面这四条配置避免eslint报@别名的错误
'import/no-unresolved': 'off',
'import/extensions': 'off',
'import/no-absolute-path': 'off',
'import/no-extraneous-dependencies': 'off',
'no-param-reassign': [
'error',
{
props: true,
ignorePropertyModificationsFor: [
'e', // for e.returnvalue
'ctx', // for Koa routing
'req', // for Express requests
'request', // for Express requests
'res', // for Express responses
'response', // for Express responses
'state', // for vuex state
'config',
],
},
],
},
};
node_modules
.DS_Store
dist
dist-ssr
*.local
.idea
.vscode
dist.zip
\ No newline at end of file
This diff is collapsed.
# vite+ts+vue3.0+vant搭建移动端项目
### 介绍
vite+ts+vue3.0+vant搭建移动端项目架构
### 软件架构
### 技术选型
- vue v3.2.25
- typescript v4.4.4
- vite v2.7.2
- vant v3.3.7
- npm v6.14.9
- node v14.13.1
### Git 贡献提交规范
- feat 增加新功能
- fix 修复问题/BUG
- style 代码风格相关无影响运行结果的
- perf 优化/性能提升
- refactor 重构
- revert 撤销修改
- test 测试相关
- docs 文档/注释
- chore 依赖更新/脚手架配置修改等
- workflow 工作流改进
- ci 持续集成
- types 类型定义文件更改
- wip 开发中
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "vite-test-project",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@types/node": "^17.0.2",
"axios": "^0.24.0",
"lib-flexible": "^0.3.2",
"postcss-pxtorem": "^6.0.0",
"qs": "^6.10.3",
"sass": "^1.45.1",
"vant": "^3.3.7",
"vconsole": "^3.14.5",
"vite-plugin-compression": "^0.3.6",
"vite-plugin-style-import": "^1.4.0",
"vue": "^3.2.25",
"vue-router": "^4.0.12",
"vuex": "^4.0.2"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.8.0",
"@typescript-eslint/parser": "^5.8.0",
"@vitejs/plugin-vue": "^2.0.0",
"eslint": "^8.5.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-vue": "^8.2.0",
"typescript": "^4.4.4",
"vite": "^2.7.2",
"vue-tsc": "^0.29.8"
},
"description": "This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.",
"main": "index.js",
"author": "",
"license": "ISC"
}
// 用 vite 创建项目,配置 postcss 需要使用 post.config.js,之前使用的 .postcssrc.js 已经被抛弃
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue({ file }) {
return file.indexOf('vant') !== -1 ? 37.5 : 75;
},
propList: ['*'],
selectorBlackList: ['.norem'], // 过滤掉.norem-开头的class,不进行rem转换
},
},
};
module.exports = {
printWidth: 80, // 单行输出(不折行)的(最大)长度
useTabs: false, // 不使用缩进符,而使用空格
tabWidth: 2, // 每个缩进的空格数
tabs: false, // 使用制表符 (tab) 缩进行而不是空格 (space)
semi: false, // 是否在语句末尾打印分号
singleQuote: true, // 是否使用单引号
// "quoteProps": "as-needed", // 仅在需要时在对象属性周围添加引号
quoteProps: 'consistent',
trailingComma: 'all', // 去除对象最末尾元素跟随的逗号
arrowParens: 'always', // 箭头函数,只有一个参数的时候,也需要括号
rangeStart: 0, // 每个文件格式化的范围是文件的全部内容
proseWrap: 'always', // 当超出print width(上面有这个参数)时就折行
endOfLine: 'lf', // 换行符使用 lf
bracketSpacing: true, // 是否在对象属性添加空格
jsxBracketSameLine: true, // 将 > 多行 JSX 元素放在最后一行的末尾,而不是单独放在下一行(不适用于自闭元素),默认false,这里选择>不另起一行
htmlWhitespaceSensitivity: 'ignore', // 指定 HTML 文件的全局空白区域敏感度, "ignore" - 空格被认为是不敏感的
jsxSingleQuote: false, // jsx 不使用单引号,而使用双引号
// eslint-disable-next-line no-dupe-keys
rangeStart: 0, // 每个文件格式化的范围是文件的全部内容
};
<template>
<!-- ontouchstart 解决ios上点击按钮没有阴影反馈的问题 -->
<div class="main" ontouchstart>
<router-view v-slot="{ Component }">
<keep-alive>
<component
:is="Component"
v-if="$route.meta.keepAlive"
:key="$route.name"
/>
</keep-alive>
<component
:is="Component"
v-if="!$route.meta.keepAlive"
:key="$route.name"
/>
</router-view>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App',
components: {},
setup() {
return {};
},
});
</script>
<style lang="scss" scoped>
.main {
width: 100%;
height: 100%;
background-color: #f2f2f2;
}
</style>
import exp from 'constants';
import request from './request';
// 获取用户详情
// eslint-disable-next-line import/prefer-default-export
export const GetUserDetail = (params: object) => request({
url: '/getUserDetail',
params,
});
// 获取部门
export const GetDepts = () => request({
method: 'get',
url: '/getDepartment',
});
export const GetDeptUser = (params) => request({
method: 'get',
url: '/getDepartmentUser',
params,
});
export const SendMessage = () => request({
url: '/sendMsg',
method: 'post',
});
export const GetUserInfo = (data) => request({
url: '/userInfo',
method: 'post',
data
})
export const GetWxCode = (path) => {
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww464eb5dddaf95145&redirect_uri=http://wx.91isoft.com/dist/#${path}&response_type=code&scope=snsapi_base#wechat_redirect`
}
import request from './request';
export interface HttpResponse {
status: number
success?: boolean
traceId?: string
data: any
}
export const login = async (data = {}): Promise<HttpResponse> => request('/接口', {
method: 'post',
data,
});
import axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { Toast } from 'vant';
import Qs from 'qs'
// 错误码
const codeMessage: Record<number, string> = {
400: '请求错误',
401: '登录已过期请重新登录',
403: '访问被禁止。',
404: '发出的请求是不存在的记录',
406: '请求的格式不可得。',
410: '请求的资源被永久删除',
422: '验证错误',
500: '服务器发生错误',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
20032: '该功能暂未对您开放',
10025: '用户不存在',
};
// 创建axios实例
const instance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API as any,
timeout: 600000,
});
const { CancelToken } = axios;
const source = CancelToken.source();
// 添加请求拦截器
instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
debugger
if(config.data && config.headers['Content-Type'] === 'application/x-www-form-urlencoded;charset=utf-8') {
config.data = Qs.stringify(config.data, { arrayFormat: 'indices', allowDots: true })
return config
}
// config
// 在发送请求之前做些什么
const headers = {
// 用crm的token发起请求
Authorization: youngDanStorage.get('token') ? youngDanStorage.get('token') : '',
'Content-Type': 'application/json',
};
if (config.headers) {
config.headers = { ...headers, ...config.headers } as any;
} else {
config.headers = headers as any;
}
config.cancelToken = source.token;
return config;
},
(error: AxiosError) => Promise.resolve(error || '服务器异常'),
);
// 添加响应拦截器
instance.interceptors.response.use(
async (response: AxiosResponse) => {
const { code, msg, message } = response.data;
if (code) {
if(code === 200) {
return response.data;
} else {
Toast(msg || message || '网络异常')
}
} else {
return response.data;
}
return response.data;
},
(error: AxiosError) => {
const { response } = error;
if (response && response.status) {
const { status, statusText } = response;
const errorText = codeMessage[status] || statusText;
Toast.fail(errorText);
} else if (!response) {
Toast.fail('您的网络发生异常,无法连接服务器');
}
return Promise.reject(error);
},
);
export default instance;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
position: relative;
width: 100%;
height: 100%;
line-height: 1.5;
font-family: PingFang SC, Source Sans Pro, Hiragino Sans GB, Helvetica Neue, Helvetica, Microsoft Yahei, arial,
sans-serif;
-webkit-tap-highlight-color: transparent;
box-sizing: border-box;
touch-action: manipulation; //禁止ios上面双击缩放页面
}
#app {
height: 100%;
}
@import "./_base.scss";
@import "./_var.scss";
\ No newline at end of file
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue';
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>;
export default component;
}
import { createApp } from 'vue';
import 'lib-flexible/flexible';// 解决自动转rem后vant组件变小的问题
import { router, setupRouter } from './router';
import setupRouterGuard from './router/guard';
import setupYoungDanStorage from '@/utils/cache';
import { setupStore } from '@/store';
import App from './App.vue';
import './assets/scss/_index.scss';
import 'vant/lib/index.css';
async function immediately(): Promise<void> {
const app = createApp(App);
setupYoungDanStorage();
// Configure store
setupStore(app);
// Configure routing
setupRouter(app);
// router-guard
setupRouterGuard(router);
// wait router ready
await router.isReady();
app.mount('#app');
}
immediately();
import type { Router } from 'vue-router';
import { Dialog } from 'vant';
import { GetWxCode } from '@/api/auth';
/*
Permission
*/
const whiteRoutes = ['/needAuth'];
function createPermissionGuard(router: Router) {
router.beforeEach(async (to, from, next) => {
if (whiteRoutes.includes(to.path)) {
return next();
}
const reg = /(^|&)code=([^&]*)(&|$)/i;
const result = window.location.search.substr(1).match(reg);
if (result) {
const code = decodeURI(result[2]);
window.youngDanStorage.set('wxCOde', code);
next();
} else {
next(false);
Dialog.confirm({
message: '是否确定授权?',
title: '提示',
}).then(async () => {
await GetWxCode(to.path);
// window.location.href = 'http://localhost:8888/?code=t_b_eDAzavIoX8c7uBwWD8Eb06um9xONMsG7nnkQ5Lg&state=#/';
});
}
});
}
export default function setupRouterGuard(router: Router):void {
createPermissionGuard(router);
}
import type { App } from 'vue';
import type { RouteRecordRaw } from 'vue-router';
import { createRouter, createWebHashHistory } from 'vue-router';
import routes from './routes';
// app router
export const router = createRouter({
history: createWebHashHistory(),
routes: routes as unknown as RouteRecordRaw[],
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
return { top: 0 };
},
});
// config router
export function setupRouter(app: App<Element>) {
app.use(router);
}
import { RouteRecordRaw } from 'vue-router';
import Home from '@/views/home/index.vue';
const HomeRoute: Array<RouteRecordRaw> = [
{
path: '/',
redirect: '/home',
},
{
path: '/home',
name: 'Home',
component: Home,
meta: {
title: '首页',
},
},
];
export default HomeRoute;
import HomeRoute from './homeRoutes';
import LoginRoute from './loginRoutes';
const routes = [
...HomeRoute,
...LoginRoute,
];
export default routes;
import { RouteRecordRaw } from 'vue-router';
import Login from '@/views/login/index.vue';
const LoginRoute: Array<RouteRecordRaw> = [
{
path: '/login',
name: 'Login',
component: Login,
meta: {
title: '登录',
},
},
];
export default LoginRoute;
import type { App } from 'vue';
import { createStore, createLogger } from 'vuex';
const debug = process.env.NODE_ENV !== 'production';
// 自动注入所有 ./modules 下的 vueX 子模块 vite的方法
const modulesFile = import.meta.globEager('./modules/*.ts') as any;
const modules = {} as any;
Object.keys(modulesFile).forEach(async (key: any) => {
const moduleName = key.replace(/^\.\/.*\/(.*)\.\w+$/, '$1');
modules[moduleName] = modulesFile[key].default;
});
export const store = createStore({
modules,
strict: debug,
plugins: debug ? [createLogger()] : [], // 操作vueX => 控制台打印
});
export function setupStore(app: App<Element>) {
app.use(store);
}
import type {
GetterTree, MutationTree, ActionTree, Module,
} from 'vuex';
export interface UserState { }
const state = (): UserState => ({});
export const getters: GetterTree<UserState, any> = {};
export const mutations: MutationTree<UserState> = {};
export const actions: ActionTree<UserState, any> = {};
export default {
namespaced: true,
getters,
mutations,
actions,
state,
} as Module<UserState, any>;
import type {
GetterTree, MutationTree, ActionTree, Module,
} from 'vuex';
export interface UserState { }
const state = (): UserState => ({});
export const getters: GetterTree<UserState, any> = {};
export const mutations: MutationTree<UserState> = {};
export const actions: ActionTree<UserState, any> = {};
export default {
namespaced: true,
getters,
mutations,
actions,
state,
} as Module<UserState, any>;
type StorageType = Storage
interface CreateStorageOptions {
prefix?: string;
safeTime?: number;
once?: boolean
}
interface SetOptions {
safeTime?: number;
once?: boolean;
}
class CustomStorage {
private prefix: string = '';
private safeTime: number = 0;
private once: boolean = false;
private store: StorageType;
constructor(storage: StorageType, config?: CreateStorageOptions) {
this.store = storage;
const { prefix, safeTime, once } = config || {};
this.prefix = prefix || '';
this.safeTime = safeTime || 0;
this.once = once || false;
}
// setItem, 配置保质期和一次性存值 合并全局
set(key: string, value: any, option?: SetOptions) {
const {
prefix, safeTime, once, store,
} = this;
const storeKey:string = `${prefix ? `${prefix}_` : ''}${key}`;
store.set(storeKey, {
time: new Date().getTime(),
once: option?.once ? option.once : once || false,
value: typeof value === 'object' ? JSON.stringify(value) : value,
});
};
get(key) {
const {
prefix, safeTime, once, store,
} = this;
const storeKey:string = `${prefix ? `${prefix}_` : ''}${key}`;
const
}
}
export const SessionStorage = new CustomStorage(sessionStorage, {
prefix: '',
safeTime: 1000 * 3600 * 72,
once: false,
});
import { createStorage as create } from './storage';
export default function setupYoungDanStorage() {
(window as any).youngDanStorage = create({
prefixKey: 'YOUNGDAN__',
});
}
import { isNullOrUnDef, isSymbol } from '@/utils/ts/is';
export interface CreateStorageParams {
prefixKey: string;
mode: 'session' | 'local';
}
/**
* 判断当前值是否能够被JSON.stringify识别
* @param data 需要判断的值
* @returns 前参数是否可以string化
*/
export function hasStringify(data: any): boolean {
if (data === undefined) {
return false;
}
if (data instanceof Function) {
return false;
}
return !isSymbol(data);
}
export const createStorage = ({
prefixKey = '',
mode = 'local',
}: Partial<CreateStorageParams> = {}) => {
if (!window.localStorage) {
throw new Error('当前环境非无法使用localStorage');
}
if (!window.sessionStorage) {
throw new Error('当前环境非无法使用sessionStorage');
}
/**
* Cache class
* 通过mode 设置 sessionStorage, localStorage,
* @class Cache
* @example
*/
const YoungDanStorage = class YoungDanStorage {
private storage: Storage;
private prefixKey?: string;
private getKey(storageKey: string) {
return `${this.prefixKey}${storageKey}`.toUpperCase();
}
/**
*
* @param {*} storage
*/
constructor() {
this.storage = mode === 'local' ? localStorage : sessionStorage;
this.prefixKey = prefixKey;
}
/**
* 设置当前
* @param key 设置当前存储key
* @param value 设置当前存储value
* @expire 过期时间(秒)
*/
set(key: string, value: any) {
if (hasStringify(value)) {
const stringData = {
timestamp: Date.now(),
value,
};
this.storage.setItem(this.getKey(key), JSON.stringify(stringData));
} else {
throw new Error('需要存储的data不支持JSON.stringify方法,请检查当前数据');
}
}
/**
* 获取数据
* @param {string} key 获取当前数据key
* @returns 存储数据
*/
get(key: string, def: any = null): any {
const val = this.storage.getItem(this.getKey(key));
if (!val) return def;
try {
const data = JSON.parse(val);
const { value, expire } = data;
if (isNullOrUnDef(expire) || expire >= new Date().getTime()) {
return value;
}
this.remove(key);
return null;
} catch (err) {
return def;
}
}
/**
* 修改存储数据的内容
* @param key 当前存储key
* @param onChange 修改函数
* @param baseValue 基础数据
*/
// eslint-disable-next-line no-unused-vars
change<T = any>(key: string, onChange: (oldValue: T) => T | null, baseValue?: any): void {
const data = this.get(key);
const newTarget = onChange(data || baseValue);
this.set(key, newTarget);
}
/**
* 移除一条数据
* @param key 移除key
*/
remove(key: string): void {
if (this.has(key)) {
this.storage.removeItem(this.getKey(key));
}
}
/**
* 清除存储中所有数据
*/
clear(): void {
this.storage.clear();
}
/**
* 判断是否存在该属性
* @param key 需要判断的key
*/
has(key: string): boolean {
return Object.prototype.hasOwnProperty.call(this.storage, this.getKey(key));
}
/**
* 返回当前存储库大小
* @returns number
*/
size(): number {
return this.storage.length;
}
/**
* 获取所有key
* @returns 回storage当中所有key集合
*/
getKeys(): Array<string> {
return Object.keys(this.storage);
}
/**
* 获取所有value
* @returns 所有数据集合
*/
getValues(): Array<string> {
return Object.values(this.storage);
}
};
return new YoungDanStorage();
};
import { Toast } from 'vant';
// 快速复制
const fastCopy = (text: any) => {
const input = document.createElement('input');
document.body.appendChild(input);
input.value = text;
input.select(); // 选中文本
document.execCommand('Copy');
Toast('复制成功');
input.remove();
};
// 点击电话调起手机打电话功能 传递进来的参数是电话号码
const makePhoneCall = (tel: number | string) => {
const AElement = document.createElement('a');
AElement.href = `tel:${tel}`;
AElement.click();
AElement.remove();
};
// 格式化数字单位
const formatNumUnit = (num: number | string) => {
const numS = Number(num);
if (numS) {
if (numS <= 10000) {
return numS;
} if (numS < 100000000) {
return `${Number((numS / 10000).toFixed(2))}w`;
}
return `${Number((numS / 100000000).toFixed(2))}亿`;
}
return 0;
};
export {
fastCopy, makePhoneCall, formatNumUnit,
};
const { toString } = Object.prototype;
export function is(val: unknown, type: string) {
return toString.call(val) === `[object ${type}]`;
}
export function isDef<T = unknown>(val?: T): val is T {
return typeof val !== 'undefined';
}
export function isUnDef<T = unknown>(val?: T): val is T {
return !isDef(val);
}
export function isArray(val: any): val is Array<any> {
return val && Array.isArray(val);
}
export function isString(val: unknown): val is string {
return is(val, 'String');
}
export function isObject(val: any): val is Record<any, any> {
return val !== null && is(val, 'Object');
}
export function isEmpty<T = unknown>(val: T): val is T {
if (isArray(val) || isString(val)) {
return val.length === 0;
}
if (val instanceof Map || val instanceof Set) {
return val.size === 0;
}
if (isObject(val)) {
return Object.keys(val).length === 0;
}
return false;
}
export function isDate(val: unknown): val is Date {
return is(val, 'Date');
}
export function isNull(val: unknown): val is null {
return val === null;
}
export function isNullAndUnDef(val: unknown): val is null | undefined {
return isUnDef(val) && isNull(val);
}
export function isNullOrUnDef(val: unknown): val is null | undefined {
return isUnDef(val) || isNull(val);
}
export function isNumber(val: unknown): val is number {
return is(val, 'Number');
}
export function isFunction(val: unknown): val is Function {
return typeof val === 'function';
}
export function isPromise<T = any>(val: unknown): val is Promise<T> {
return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch);
}
export function isBoolean(val: unknown): val is boolean {
return is(val, 'Boolean');
}
export function isRegExp(val: unknown): val is RegExp {
return is(val, 'RegExp');
}
export function isSymbol(val: any): boolean {
return typeof val === 'symbol';
}
export function isWindow(val: any): val is Window {
return typeof window !== 'undefined' && is(val, 'Window');
}
export function isElement(val: unknown): val is Element {
return isObject(val) && !!val.tagName;
}
export const isServer = typeof window === 'undefined';
export const isClient = !isServer;
export function isUrl(path: string): boolean {
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
return reg.test(path);
}
<template>
<div class="public-home">
<div v-if="userJson">
{{ userJson }}
</div>
<Button type="success" size="small" round @click="getUserDetail">
获取用户详情
</Button>
<div v-if="userDetailJson">
{{ userDetailJson }}
</div>
<Button type="primary" size="small" round @click="getDepts">
获取部门列表
</Button>
<div v-if="deptJson">
{{ deptJson }}
</div>
<Button type="danger" size="small" round @click="getDeptUsers">
获取部门下用户信息
</Button>
<div v-if="deptUserJson">
{{ deptUserJson }}
</div>
<Button type="warning" size="small" round @click="sendMessage">
发送消息
</Button>
</div>
</template>
<script lang="ts" setup>
import { Button, Dialog } from 'vant';
import { ref, onMounted } from 'vue';
import {
GetUserDetail, GetDepts, GetDeptUser, SendMessage, GetUserInfo,
} from '@/api/auth';
const userDetailJson = ref('');
const deptJson = ref('');
const deptUserJson = ref('');
const userJson = ref('');
const getUserDetail = () => {
userDetailJson.value = '';
GetUserDetail({
userId: 'LuZhuangZhuang',
}).then((res) => {
const { data } = res;
userDetailJson.value = data && typeof data === 'object' ? JSON.stringify(data) : data;
});
};
const getDepts = () => {
deptJson.value = '';
GetDepts().then((res) => {
const { data } = res;
deptJson.value = data && typeof data === 'object' ? JSON.stringify(data) : data;
});
};
const getDeptUsers = () => {
deptUserJson.value = '';
GetDeptUser({
departmentId: '1',
}).then((res) => {
const { data } = res;
deptJson.value = data && typeof data === 'object' ? JSON.stringify(data) : data;
});
};
const sendMessage = () => {
SendMessage();
};
onMounted(() => {
if (window.youngDanStorage.get('wxCode')) {
Dialog.alert({
message: `${window.youngDanStorage.get('wxCode')}`,
title: 'code',
}).then(() => {
GetUserInfo({
code: `${window.youngDanStorage.get('wxCode')}`
}).then(res => {
userJson.value = res && typeof res === 'object' ? JSON.stringify(res) : res;
})
})
}
});
</script>
<style lang="scss" scoped>
.public-home {
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
padding: 0 28px;
& > div {
width: 100%;
word-break: break-all;
font-weight: 500;
font-size: 32px;
}
}
</style>
<template>
<div class="LoginWrapper">
<Button type="success" round block @click="BackHome">
点我返回
</Button>
</div>
</template>
<script lang="ts" setup>
import { Button } from 'vant';
import { useRouter } from 'vue-router';
const router = useRouter();
const BackHome = () => {
router.back();
};
</script>
<style lang="scss" scoped>
.LoginWrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 0 30px;
}
</style>
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
// 解析非相对模块名的基准目录
"baseUrl": ".",
// 模块名到基于 baseUrl的路径映射的列表。
"paths": {
"@": ["src"],
"@/*": ["src/*"],
},
// 忽略所有的声明文件( *.d.ts)的类型检查。
"skipLibCheck": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","types/**/*.d.ts"]
}
/* eslint-disable no-shadow */
export {};
/* eslint-disable no-unused-vars */
interface YoungDanStorage {
set(key: string, value: any): void;// 设置缓存
get(key: string, def?: any): any;// 获取缓存
change<T = any>(key: string, onChange: (oldValue: T) => T | null, baseValue?: any): void;// 修改缓存
remove(key: string): void;// 移除缓存
clear(): void;// 清空缓存(所有)
has(key: string): boolean;// 判断是否存在某个缓存
size(): number;// 读取某个缓存的长度
getKeys(): Array<string>;// storage当中所有key集合
getValues(): Array<any>;// 所有数据集合
}
declare global {
declare interface Window {
youngDanStorage: YoungDanStorage;
}
declare const youngDanStorage: YoungDanStorage;// 全局定义youngDanStorage 可直接读取
}
import { defineConfig } from 'vite';
import { resolve } from 'path';
import vue from '@vitejs/plugin-vue';
import viteCompression from 'vite-plugin-compression';
import styleImport from 'vite-plugin-style-import';
// https://vitejs.dev/config/
const buildTimeStep = new Date().getTime()
export default defineConfig({
plugins: [
vue(),
viteCompression({
ext: '.gz', // gz br
algorithm: 'gzip', // brotliCompress gzip
deleteOriginFile: false, // 打包完成后删除源文件
}),
styleImport({}),
],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
base: './', // 打包基础路径 不配置打包后可能会找不到资源
server: {
host: '0.0.0.0',
open: true,
proxy: {
'/qy-api': {
target: 'http://117.122.212.102:8092/qy-api', // 测试服务
changeOrigin: true,
rewrite: (path) => path.replace(/^\/qy-api/, ''),
},
'/wx': {
target: 'https://open.weixin.qq.com', // 测试服务
changeOrigin: true,
rewrite: (path) => path.replace(/^\/wx/, ''),
},
},
port: 8888, // 启动时的默认占用端口
},
build: {
outDir: 'dist',
rollupOptions: {
output: {
entryFileNames: `assets/[name].${buildTimeStep}.js`,
chunkFileNames: `assets/[name].${buildTimeStep}.js`,
assetFileNames: `assets/[name].${buildTimeStep}.[ext]`
}
}
}
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment