hookehuyr

🎉 init: 项目初始化

# port
VITE_PORT = 8106
# 反向代理服务器地址
VITE_PROXY_TARGET = https://oa-dev.onwall.cn
# VITE_PROXY_TARGET = https://oa.onwall.cn
# API请求前缀
VITE_PROXY_PREFIX = /srv/
# 打包输出文件夹名称
VITE_OUTDIR = hager
# 是否开启调试
VITE_CONSOLE = 0
# appID相关
VITE_APPID=微信appID
# 资源公共路径
VITE_BASE = /
# 测试open-id
# VITE_OPENID = api-test-openid
# VITE_OPENID = o8BRf1gLDWieH3Y3JvbrI_4IjaME
VITE_OPENID = oJLZq5t9PIKLW9tm1oSUNAuPwssA
# VITE_OPENID = oJLZq5uT_6GwIh2tQWh1F9IoHZ3U
# B端账号
VITE_ID = 13761653761
# 验证码
VITE_PIN =
###
# @Date: 2024-09-26 13:36:06
# @LastEditors: hookehuyr hookehuyr@gmail.com
# @LastEditTime: 2024-09-26 13:38:31
# @FilePath: /hager/.env.production
# @Description: 文件描述
###
# 资源公共路径
VITE_BASE = /f/hager/
# 测试open-id
VITE_APP_OPENID =
# B端账号
VITE_APP_ID =
# 验证码
VITE_APP_PIN =
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.history
.vscode
海格电器自适应网页
......
export function createProxy(prefix, target) {
const ret = {};
ret[prefix] = {
target,
changeOrigin: true,
ws: true,
// rewrite: (path) => path.replace(/^\/api/, '')
// rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
}
return ret
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{
"name": "hager-project",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"axios": "^1.7.5",
"dayjs": "^1.11.13",
"element-ui": "^2.15.14",
"mui-player": "^1.8.1",
"sass": "1.55.0",
"vue": "2.7.13",
"vue-router": "3.6.5"
},
"devDependencies": {
"@vitejs/plugin-legacy": "^5.4.2",
"@vitejs/plugin-vue": "^5.1.2",
"@vitejs/plugin-vue2": "^2.3.1",
"less": "^4.2.0",
"path-browserify": "^1.0.1",
"qs": "^6.13.0",
"sass-embedded": "1.55.0",
"vite": "^5.4.1",
"vite-plugin-dynamic-import": "^1.5.0"
}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
<template>
<div>
<router-view></router-view>
</div>
</template>
<script setup>
</script>
<style lang="less" scoped>
</style>
import { fn, fetch, uploadFn } from '@/api/fn';
const Api = {
SMS: '/srv/?a=sms',
TOKEN: '/srv/?a=upload',
SAVE_FILE: '/srv/?a=upload&t=save_file',
}
/**
* @description: 发送验证码
* @param {*} phone 手机号码
* @returns
*/
export const smsAPI = (params) => fn(fetch.post(Api.SMS, params));
/**
* @description: 获取七牛token
* @param {*} filename 文件名
* @param {*} file 图片base64
* @returns
*/
export const qiniuTokenAPI = (params) => fn(fetch.stringifyPost(Api.TOKEN, params));
/**
* @description: 上传七牛
* @param {*}
* @returns
*/
export const qiniuUploadAPI = (url, data, config) => uploadFn(fetch.basePost(url, data, config));
/**
* @description: 保存图片
* @param {*} format
* @param {*} hash
* @param {*} height
* @param {*} width
* @param {*} filekey
* @returns
*/
export const saveFileAPI = (params) => fn(fetch.stringifyPost(Api.SAVE_FILE, params));
/*
* @Date: 2024-08-26 13:51:57
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-08-26 13:57:27
* @FilePath: /vite-project/src/api/fn.js
* @Description: 文件描述
*/
import axios from '@/utils/axios';
import { Message } from 'element-ui';
import qs from 'Qs'
/**
* 网络请求功能函数
* @param {*} api 请求axios接口
* @returns 请求成功后,获取数据
*/
export const fn = (api) => {
return api
.then(res => {
if (res.data.code === 1) {
return res.data || true;
} else {
// tslint:disable-next-line: no-console
console.warn(res);
if (!res.data.show) return false;
Message({
message: res.data.msg,
type: 'warning'
});
return false;
}
})
.catch(err => {
// tslint:disable-next-line: no-console
console.error(err);
return false;
})
.finally(() => { // 最终执行
})
}
/**
* 七牛返回格式
* @param {*} api
* @returns
*/
export const uploadFn = (api) => {
return api
.then(res => {
if (res.statusText === 'OK') {
return res.data || true;
} else {
// tslint:disable-next-line: no-console
console.warn(res);
if (!res.data.show) return false;
Toast({
icon: 'close',
message: res.data.msg
});
return false;
}
})
.catch(err => {
// tslint:disable-next-line: no-console
console.error(err);
return false;
})
}
/**
* 统一 GET/POST 不同传参形式
*/
export const fetch = {
get: function (api, params) {
return axios.get(api, { params })
},
post: function (api, params) {
return axios.post(api, params)
},
stringifyPost: function (api, params) {
return axios.post(api, qs.stringify(params))
},
basePost: function (url, data, config) {
return axios.post(url, data, config)
}
}
import { fn, fetch } from '@/api/fn';
const Api = {
MAP: '/srv/?a=map',
};
export const mapAPI = (params) => fn(fetch.get(Api.MAP, params));
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
\ No newline at end of file
<!--
* @Date: 2024-08-28 10:17:07
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-08-29 16:10:19
* @FilePath: /vue2_vite_web/src/components/navbar.vue
* @Description: 文件描述
-->
<template>
<div class="navbar-container">
<div class="big-navbar" v-if="!isMobile"></div>
<div class="small-navbar" v-else></div>
</div>
</template>
<script setup>
const isMobile = ref(window.innerWidth < 768)
const updateWindowSize = () => {
isMobile.value = window.innerWidth < 768
}
// 使用watch来监听窗口大小变化(也可以使用其他方式)
watch(
() => window.innerWidth,
(newVal, oldVal) => {
updateWindowSize()
},
{ immediate: false },
)
onMounted(() => {
window.addEventListener('resize', updateWindowSize)
})
onBeforeUnmount(() => {
window.removeEventListener('resize', updateWindowSize)
})
</script>
<style lang="scss" scoped>
// 也可以使用媒体查询来设置一些样式
@media (max-width: 768px) {
.navbar {
background: rgb(255, 255, 255);
}
}
</style>
<template>
<div ref="animatedElement" :style="computedStyle">
<slot></slot>
</div>
</template>
<script>
// 页面滚动时,元素缓慢上升效果, 视觉差效果组件
export default {
name: 'slideIn',
props: {
duration: { // 动画持续时间
type: Number,
default: 1000
},
easing: { // 动画缓动效果
type: String,
default: 'ease'
},
distance: { // 动画距离
type: Number,
default: 100
}
},
data() {
return {
hasAnimated: false // 是否已经动画过
}
},
computed: {
computedStyle() {
return {
opacity: this.hasAnimated ? 1 : 0,
transform: this.hasAnimated ? 'translateY(0)' : `translateY(${this.distance}px)`,
transition: `transform ${this.duration}ms ${this.easing}, opacity ${this.duration}ms ${this.easing}`
}
}
},
mounted() {
if (typeof window !== 'undefined' && 'IntersectionObserver' in window) { // 检测是否支持IntersectionObserver
this.createObserver() // 创建IntersectionObserver
} else {
// 如果不支持IntersectionObserver,则使用scroll事件来实现动画
this.observeScroll()
}
},
methods: {
createObserver() {
const observer = new IntersectionObserver(entries => { // IntersectionObserver回调函数
entries.forEach(entry => { // 遍历每个观察目标
if (entry.isIntersecting && !this.hasAnimated) { // 如果目标进入视口并且没有动画过
this.hasAnimated = true // 标记动画过
observer.unobserve(entry.target) // 停止观察
}
})
}, { threshold: 0.1 }) // 观察阈值,表示目标在视口的百分比
observer.observe(this.$refs.animatedElement) // 观察目标
},
observeScroll() {
const onScroll = () => { // scroll事件回调函数
if (this.isInViewport(this.$refs.animatedElement) && !this.hasAnimated) { // 如果目标在视口并且没有动画过
this.hasAnimated = true // 标记动画过
window.removeEventListener('scroll', onScroll) // 停止监听scroll事件
}
}
window.addEventListener('scroll', onScroll) // 监听scroll事件
},
isInViewport(el) { // 判断目标是否在视口
const rect = el.getBoundingClientRect()
return rect.top < window.innerHeight && rect.bottom > 0
}
}
}
</script>
<!--
* @Date: 2024-09-24 18:06:55
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-09-25 09:59:56
* @FilePath: /vue2_vite_web/src/components/videoPlayer.vue
* @Description: 文件描述
-->
<template>
<div class="">
<div id="mui-player">
</div>
<div v-if="status === 'play'" @click="play" style="position: absolute; top: 50%; left: 50%;">play</div>
<div v-if="status === 'pause'" @click="pause" style="position: absolute; top: 50%; left: 50%;">pause</div>
</div>
</template>
<script>
import 'mui-player/dist/mui-player.min.css'
import MuiPlayer from 'mui-player'
export default {
data () {
return {
video: null,
status: 'play',
}
},
mounted () {
// 初始化 MuiPlayer 插件,MuiPlayer 方法传递一个对象,该对象包括所有插件的配置
var mp = new MuiPlayer({
container:'#mui-player',
title: '',
pageHead: false,
src:'https://gd-pri.jinshujufiles.com/en/g7D0MT/ltkASOw4yq0lJI0b-VH00VNz7zCs_field_20_1657944201.MOV?token=7NK_Z1IEoKaIY6I9RXzO4b9uQPwuwdvnlGbzHZmF:iYFNizzrqTFRuDPzUdtWDSrUOtA=:eyJTIjoiZ2QtcHJpLmppbnNodWp1ZmlsZXMuY29tL2VuL2c3RDBNVC9sdGtBU093NHlxMGxKSTBiLVZIMDBWTno3ekNzX2ZpZWxkXzIwXzE2NTc5NDQyMDEuTU9WKiIsIkUiOjE5NzM1MTM3NTh9',
poster: 'https://gd-pri.jinshujufiles.com/en/g7D0MT/FqGDEvU9encwLEBGGj5y3_9fZ5VR_field_74_1657944218.jpeg?token=7NK_Z1IEoKaIY6I9RXzO4b9uQPwuwdvnlGbzHZmF:5dtH0Gbayh4jNtDMHK4o0D7X5Vs=:eyJTIjoiZ2QtcHJpLmppbnNodWp1ZmlsZXMuY29tL2VuL2c3RDBNVC9GcUdERXZVOWVuY3dMRUJHR2o1eTNfOWZaNVZSX2ZpZWxkXzc0XzE2NTc5NDQyMTguanBlZyoiLCJFIjoxOTczNTEzNzU4fQ==',
videoAttribute: [
// 声明启用同层播放, 不让会自动全屏播放
{ attrKey: 'webkit-playsinline', attrValue: 'webkit-playsinline' },
{ attrKey: 'playsinline', attrValue: 'playsinline' },
{ attrKey: 'x5-video-player-type', attrValue: 'h5-page' },
],
});
const video = mp.video();
mp.on('ready',() => {
this.video = video;
});
},
methods: {
play () {
this.video.play();
this.status = 'pause';
},
pause () {
this.video.pause();
this.status = 'play';
}
}
}
</script>
<style lang="less" scoped>
</style>
/*
* @Date: 2024-08-26 10:12:56
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-09-24 18:05:09
* @FilePath: /vue2_vite_web/src/main.js
* @Description: 文件描述
*/
import "@babel/polyfill";
import Vue from "vue";
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import 'element-ui/lib/theme-chalk/display.css'; // 基于断点的隐藏类,用于在某些条件下隐藏元素
import '@/styles/element-ui/element-variables.scss' // 自定义主题, 不需要展示屏蔽
Vue.use(VueRouter);
Vue.use(ElementUI);
new Vue({
router,
render: (h) => h(App),
})
.$mount("#app");
/*
* @Date: 2024-08-26 10:42:15
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-08-26 10:53:44
* @FilePath: /vite-project/src/route.js
* @Description: 文件描述
*/
export default [{
path: '/',
name: '首页',
component: () => import('@/views/index'),
meta: {
},
children: []
}]
/*
* @Date: 2024-08-26 10:42:15
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-08-26 10:46:21
* @FilePath: /vite-project/src/router.js
* @Description: 文件描述
*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import ConfigRouter from './route.js'
Vue.use(VueRouter)
const router = new VueRouter({
history: false,
hashbang: true,
base: '/',
routes: ConfigRouter
})
router.beforeEach((to, from, next) => {
next()
})
router.afterEach((to, from, next) => {
// store.commit('updateLoadingStatus', false)
})
export default router
@import "../variables.scss";
/* 改变主题色变量 */
$--color-primary: $style-el--color-primary;
$--color-white: $style-el--color-white;
/* 改变 icon 字体路径变量,必需 */
$--font-path: 'element-ui/lib/theme-chalk/fonts';
@import "element-ui/packages/theme-chalk/src/index";
This diff is collapsed. Click to expand it.
/*需要切换的颜色变量*/
$style-el--color-demo: transparent;
$style-el--color-demo1:red;
/* element颜色值声明
* 统一前缀 $style-el
* 后接element中变量值
*/
$style-el--color-primary: #C2915F;
$style-el--color-white: #ffffff;
/*定义方法*/
@mixin color_primary() {
/*判断匹配*/
[data-theme="theme0"] & {
background-color: $style-el--color-demo;
}
[data-theme="theme1"] & {
background-color: $style-el--color-demo1;
}
}
// tab组件
@mixin tabs_color() {
[data-theme="theme0"] & {
color: #fff;
text-shadow: 0 1px 2px rgb(0 0 0 / 50%);
}
}
// dialog组件
@mixin dialog_color() {
[data-theme="theme0"] & {
background: linear-gradient(218deg, #0c386b 0%, #051934 100%);
color: #fff;
}
}
This diff is collapsed. Click to expand it.
File mode changed
/*
* @Date: 2022-06-20 01:22:50
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-06-20 01:23:18
* @FilePath: /tswj/src/composables/useMonitorKeyboard.js
* @Description: 文件描述
*/
/**
* @class 监听虚拟键盘
* @classdesc 监听虚拟键盘弹出隐藏
* @public onEnd 结束监听虚拟键盘
* @public onShow 传递一个回调 监听虚拟键盘弹出
* @public onHidden 传递一个回调 监听虚拟键盘隐藏
*/
class MonitorKeyboard {
constructor() {
this.type = this.IsIA();
this.originalHeight = window.innerHeight;
}
/**
* @function IsIA 获取设备类型
* @param 1 Android 2 iOS
*/
IsIA = () => {
const userAgent = typeof window === 'object' ? window.navigator.userAgent : '';
if (/android/i.test(userAgent)) {
return 1;
} else if (/iPhone|iPod|iPad/i.test(userAgent)) {
return 2;
}
}
// Android系统
onResize = () => {
//键盘弹起与隐藏都会引起窗口的高度发生变化
const resizeHeight = window.innerHeight;
if (this.originalHeight - resizeHeight > 50) {
this.show('Android系统: 软键盘弹出');
} else {
this.hidden('Android系统: 软键盘收起');
}
}
// iOS获取焦点
onFocusin = () => {
this.show('iOS系统:软键盘弹出');
}
// iOS失去焦点
onFocusout = () => {
this.hidden('iOS系统:软键盘收起');
}
/**
* @function onStart 开始监听虚拟键盘
*/
onStart = () => {
if (this.type == 1) {
// 获取窗口的高度
window.addEventListener('resize', this.onResize);
}
if (this.type == 2) {
// iOS系统
window.addEventListener('focusin', this.onFocusin);
window.addEventListener('focusout', this.onFocusout);
}
}
/**
* @function onEnd 结束监听虚拟键盘
*/
onEnd = () => {
if (this.type == 1) {
//获取窗口的高度
window.removeEventListener('resize', this.onResize);
}
if (this.type == 2) {
window.removeEventListener('focusin', this.onFocusin);
window.removeEventListener('focusout', this.onFocusout);
}
}
/**
* @function onShow 传递一个回调函数
* @param 虚拟键盘弹出时触发
*/
onShow = (fn) => {
this.show = fn;
}
/**
* @function onHidden 传递一个回调函数
* @param 虚拟键盘隐藏时触发
*/
onHidden = (fn) => {
this.hidden = fn;
}
}
export default MonitorKeyboard
/*
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-28 10:17:40
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-09-03 16:01:59
* @FilePath: /vue2_vite_web/src/utils/axios.js
* @Description:
*/
import axios from 'axios';
import router from '@/router';
import qs from 'Qs'
import { strExist } from '@/utils/tools'
// import { parseQueryString } from '@/utils/tools'
axios.defaults.params = {
f: 'tools',
};
/**
* @description 请求拦截器
*/
axios.interceptors.request.use(
config => {
// const url_params = parseQueryString(location.href);
// GET请求默认打上时间戳,避免从缓存中拿数据。
const timestamp = config.method === 'get' ? (new Date()).valueOf() : '';
/**
* POST PHP需要修改数据格式
* 序列化POST请求时需要屏蔽上传相关接口,上传相关接口序列化后报错
*/
config.data = config.method === 'post' && !strExist(['a=upload', 'upload.qiniup.com'], config.url) ? qs.stringify(config.data) : config.data;
// 绑定默认请求头
config.params = { ...config.params, timestamp }
return config;
},
error => {
// 请求错误处理
return Promise.reject(error);
});
/**
* @description 响应拦截器
*/
axios.interceptors.response.use(
response => {
// 默认显示错误提示
response.data.show = true;
if (response.data.code === 401) {
// 特殊标识-带此标识报错不显示
response.data.show = false;
/**
* 未授权跳转登录页
* 带着上一个页面的信息, 授权完成后 返回当前页面
*/
router.replace({ path: '/auth', query: { href: location.hash, prefixAPI } });
}
return response;
},
error => {
return Promise.reject(error);
});
export default axios;
/*
* @Date: 2022-05-16 17:21:45
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-06-29 17:00:15
* @FilePath: /tswj/src/utils/generateRoute.js
* @Description: 文件描述
*/
/**
* 根据后台返回的路径,生成页面的组件模版
* @param {*} component
* @returns 模版地址
*/
function loadView(component) {
return () => import(`../views/${component}.vue`)
}
/**
* 生成路由结构
* @param {*} routes
*/
const generateRoutes = (routes) => {
const arr = []
routes.forEach(route => {
const router = {}
const {
path,
redirect,
name,
component,
keepAlive,
meta,
children
} = route
router.path = path
redirect && (router.redirect = redirect)
name && (router.name = name)
router.component = loadView(component)
keepAlive && (router.keepAlive = keepAlive)
meta && (router.meta = meta)
router.children = !Array.isArray(children) || generateRoutes(children);
arr.push(router)
})
return arr
}
export default generateRoutes;
import wx from 'weixin-js-sdk'
import axios from '@/utils/axios';
const fn = (to) => {
// 路由名
let ruleName = location.href.split('#/')[1].split('?')[0];
const icon = 'https://cdn.lifeat.cn/webappgroup/betterLifelogo.png'
const shareInfoMap = {
'client/index': {
title: '童声无界',
desc: '引导页',
icon
},
'client/chooseSchool': {
title: '选择幼儿园',
desc: '引导页',
icon
},
default: {
title: to.name,
desc: window.location.href,
icon
},
}
let infoMap = shareInfoMap[ruleName] ? shareInfoMap[ruleName] : shareInfoMap['default'];
// console.warn(ruleName);
console.warn(infoMap);
console.warn(wx);
console.warn(axios);
}
export default fn
// 这个判断后加的为了减少请求次数,据后端说有次数限制,当需要分享的页面才去请求接口。
// if (shareInfoMap[ruleName]) {
// // request 是封装的请求
// request.post('/wxmp/sign/jsSdk', {
// url: location.href,
// }).then(res => {
// let { timestamp, nonceStr, signature, appId } = res;
// wx.config({
// debug: false,
// appId,
// timestamp,
// nonceStr,
// signature,
// jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
// });
// wx.error(function (errres) {
// console.info(errres)
// })
// wx.ready(() => { //需在用户可能点击分享按钮前就先调用
// console.info('ready')
// //分享朋友
// wx.updateAppMessageShareData({
// title: infoMap.title, // 分享标题
// desc: infoMap.desc, // 分享描述
// link: location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
// imgUrl: infoMap.icon, // 分享图标
// success: function () {
// console.info("成功")
// // 设置成功
// },
// fail: function (erres) {
// console.info('失败:', erres)
// }
// })
// //分享到 朋友圈
// wx.updateTimelineShareData({
// title: infoMap.title, // 分享标题
// link: location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
// imgUrl: infoMap.icon, // 分享图标
// success: function () {
// console.info("成功")
// // 设置成功
// },
// fail: function (erres) {
// console.info('失败:', erres)
// }
// })
// });
// }).catch(err => {
// console.info('err:', err)
// })
// }
\ No newline at end of file
/*
* @Date: 2022-04-18 15:59:42
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-08-07 13:31:59
* @FilePath: /map-demo/src/utils/tools.js
* @Description: 文件描述
*/
import dayjs from 'dayjs';
// 格式化时间
const formatDate = (date) => {
return dayjs(date).format('YYYY-MM-DD HH:mm');
};
/**
* @description 判断浏览器属于平台
* @returns
*/
const wxInfo = () => {
let u = navigator.userAgent;
let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端或者uc浏览器
let isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
let uAgent = navigator.userAgent.toLowerCase();
let isTable = (uAgent.match(/MicroMessenger/i) == 'micromessenger') ? true : false;
let isPC = uAgent.match(
/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone|micromessenger)/i,
)
? false
: true;
return {
isAndroid,
isiOS,
isTable,
isPC,
};
};
/**
* @description 判断多行省略文本
* @param {*} id 目标dom标签
* @returns
*/
const hasEllipsis = (id) => {
let oDiv = document.getElementById(id);
let flag = false;
if (oDiv.scrollHeight > oDiv.clientHeight) {
flag = true
}
return flag
}
/**
* @description 解析URL参数
* @param {*} url
* @returns
*/
const parseQueryString = url => {
var json = {};
var arr = url.indexOf('?') >= 0 ? url.substr(url.indexOf('?') + 1).split('&') : [];
arr.forEach(item => {
var tmp = item.split('=');
json[tmp[0]] = tmp[1];
});
return json;
}
/**
* 字符串包含字符数组中字符的状态
* @param {*} array 字符数组
* @param {*} str 字符串
* @returns 包含状态
*/
const strExist = (array, str) => {
const exist = array.filter(arr => {
if (str.indexOf(arr) >= 0) return str;
})
return exist.length > 0
}
export { formatDate, wxInfo, hasEllipsis, parseQueryString, strExist };
import VConsole from 'vconsole';
// const vConsole = new VConsole();
let vConsole = '';
// 或者使用配置参数来初始化,详情见文档
if (+import.meta.env.VITE_CONSOLE) {
vConsole = new VConsole({ theme: 'dark' });
}
export default vConsole
<!--
* @Date: 2024-08-27 10:06:30
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-09-26 13:37:46
* @FilePath: /hager/src/views/index.vue
* @Description: 文件描述
-->
<template>
<div></div>
</template>
<script>
export default {
components: {},
data () {
return {
}
},
async mounted () {
},
methods: {
}
}
</script>
<style lang="less" scoped>
</style>
{
"compilerOptions": {
/* 基本选项 */
"target": "esnext", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "CommonJS", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [ // 指定要包含在编译中的库文件
"esnext",
"dom",
"dom.iterable",
"scripthost"
],
"allowJs": true, // 允许编译 javascript 文件
// "checkJs": true, // 报告 javascript 文件中的错误
"jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
// "declaration": true, // 生成相应的 '.d.ts' 文件
// "sourceMap": true, // 生成相应的 '.map' 文件
// "outFile": "./", // 将输出文件合并为一个文件
"outDir": "./", // 指定输出目录
// "rootDir": "./", // 用来控制输出目录结构 --outDir.
"removeComments": true, // 删除编译后的所有的注释
// "noEmit": true, // 不生成输出文件
"importHelpers": true, // tslib 导入辅助工具函数
"isolatedModules": false, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似)
/* 严格的类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
// "noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错
// "strictNullChecks": true, // 启用严格的 null 检查
// "noImplicitThis": true, // this 表达式值为 any 类型的时候,生成一个错误
// "alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
/* 额外的检查 */
"noUnusedLocals": true, // 有未使用的变量时,抛出错误
"noUnusedParameters": true, // 有未使用的参数时,抛出错误
"noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch case 语句贯穿)
/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": ".", // 用于解析非相对模块名称的基目录
"paths": { // 模块名到基于 baseUrl 的路径映射的列表
"@/*": [
"src/*"
]
},
// "rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
// "typeRoots": [], // 包含类型声明的文件列表
"types": [ // 需要包含的类型声明文件名列表
// "webpack-env",
"vite/client",
"lodash",
"moment",
"node",
"jquery",
],
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。
/* Source Map Options */
// "sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
// "mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
// "inlineSourceMap": true, // 生成单个 sourcemaps 文件,而不是将 sourcemaps 生成不同的文件
// "inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap --sourceMap 属性
/* 其他选项 */
// "experimentalDecorators": true, // 启用装饰器
// "emitDecoratorMetadata": true, // 为装饰器提供元数据的支持
"esModuleInterop": true, // 可以在es6中导入commonjs
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
],
"vueCompilerOptions": {
"target": 2,
"experimentalSuppressInvalidJsxElementTypeErrors": true
}
}
/*
* @Date: 2024-08-26 10:12:56
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-08-29 17:50:26
* @FilePath: /vue2_vite_web/vite.config.js
* @Description: 文件描述
*/
// import vue from '@vitejs/plugin-vue'
import vue from "@vitejs/plugin-vue2";
import legacy from "@vitejs/plugin-legacy";
import dynamicImport from 'vite-plugin-dynamic-import';
import { defineConfig, loadEnv } from 'vite';
import { createProxy } from './build/proxy'
// var path = require('path');
import path from 'path-browserify';
// const fs = require('fs');
// https://vitejs.dev/config/
export default ({ command, mode }) => {
const root = process.cwd();
const viteEnv = loadEnv(mode, root);
// let isProd = (command === 'serve'); // 情景配置是否为开发模式 serve 或 build
return defineConfig({
base: viteEnv.VITE_BASE, // 开发或生产环境服务的公共基础路径。
plugins: [
vue(),
legacy({
targets: ["android 4", "ios 8", "chrome 52", "ie 11"],
additionalLegacyPolyfills: ["regenerator-runtime/runtime"],
renderLegacyChunks: true,
polyfills: [
"es.symbol",
"es.array.filter",
"es.promise",
"es.promise.finally",
"es/map",
"es/set",
"es.array.for-each",
"es.object.define-properties",
"es.object.define-property",
"es.object.get-own-property-descriptor",
"es.object.get-own-property-descriptors",
"es.object.keys",
"es.object.to-string",
"web.dom-collections.for-each",
"esnext.global-this",
"esnext.string.match-all",
],
}),
dynamicImport(),
],
publicDir: 'public', // 作为静态资源服务的文件夹。这个目录中的文件会在开发中被服务于 /,在开发模式时,会被拷贝到 outDir 的根目录,并没有转换,永远只是复制到这里。该值可以是文件系统的绝对路径,也可以是相对于项目的根目录路径。
// cacheDir: '', // 存储缓存文件的目录。此目录下会存储预打包的依赖项或 vite 生成的某些缓存文件,使用缓存可以提高性能。如需重新生成缓存文件,你可以使用 --force 命令行选项或手动删除目录。此选项的值可以是文件的绝对路径,也可以是以项目根目录为基准的相对路径。
resolve: {
alias: {
// 将会被传递到 @rollup/plugin-alias 作为 entries 的选项。也可以是一个对象,或一个 { find, replacement } 的数组. 当使用文件系统路径的别名时,请始终使用绝对路径。相对路径的别名值会被原封不动地使用,因此无法被正常解析。 更高级的自定义解析方法可以通过 插件 实现。
'@': path.resolve(__dirname, 'src'),
'@components': path.resolve(__dirname, 'src/components'),
'@composables': path.resolve(__dirname, 'src/composables'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@images': path.resolve(__dirname, 'src/assets/images'),
'@css': path.resolve(__dirname, 'src/assets/css'),
'@mock': path.resolve(__dirname, 'src/assets/mock'),
common: path.resolve(__dirname, 'src/common'),
},
// dedupe: [''], // 如果你在你的应用程序中有相同依赖的副本(比如 monorepos),使用这个选项来强制 Vite 总是将列出的依赖关系解析到相同的副本(从项目根目录)。
// conditions: [''], // 在解析包的 情景导出 时允许的附加条件。
// mainFields: [''], // package.json 中,在解析包的入口点时尝试的字段列表。注意,这比从 exports 字段解析的情景导出优先级低:如果一个入口点从 exports 成功解析,主字段将被忽略。
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'], // 导入时想要省略的扩展名列表。注意,不 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会干扰 IDE 和类型支持。
},
logLevel: 'info', // 调整控制台输出的级别,默认为 'info'。
// clearScreen: true, // 设为 false 可以避免 Vite 清屏而错过在终端中打印某些关键信息。命令行模式下请通过 --clearScreen false 设置。
server: {
host: '0.0.0.0',
port: viteEnv.VITE_PORT, // 本地服务端口
// strictPort: true, // 设为true时若端口已被占用则会直接退出, 而不是尝试下一个可用端口
// https: {
// key: fs.readFileSync(path.resolve(__dirname, 'keys/localhost+2-key.pem')),
// cert: fs.readFileSync(path.resolve(__dirname, 'keys/localhost+2.pem')),
// },
// open: false, // 在服务器启动时自动在浏览器中打开应用程序. 当此值为字符串时, 会被当作URL的路径名.
// proxy: { // 代理
// '/srv/': {
// // target: 'http://voice.onwall.cn',
// target: viteEnv.VITE_PROXY_TARGET,
// changeOrigin: true,
// // rewrite: (path) => path.replace(/^\/api/, '')
// },
// },
proxy: createProxy(viteEnv.VITE_PROXY_PREFIX, viteEnv.VITE_PROXY_TARGET),
// cors: '', // 为开发服务器配置 CORS。默认启用并允许任何源,传递一个 选项对象 来调整行为或设为 false 表示禁用。
// force: '', // 设置为 true 强制使依赖预构建。
// hmr: '', // 禁用或配置 HMR 连接(用于 HMR websocket 必须使用不同的 http 服务器地址的情况)。 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层。
// watch: '', // 传递给 chokidar 的文件系统监视器选项。
},
build: {
// outDir: 'voice', // 指定输出路径(相对于项目根目录).
outDir: viteEnv.VITE_OUTDIR, // 指定输出路径(相对于项目根目录).
assetsDir: 'static',
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
},
input: {
// 多页面应用模式, 打包时配置,运行配置要处理root
main: path.resolve(__dirname, 'index.html'),
// mono1: path.resolve(__dirname, 'src/packages/mono1/index.html'),
// mono2: path.resolve(__dirname, 'src/packages/mono2/index.html'),
},
},
target: 'es2015'
},
});
};
This diff could not be displayed because it is too large.