hookehuyr

🎉 init: 项目初始化

dist/
deploy_versions/
.temp/
.rn_temp/
node_modules/
.DS_Store
.swc
.history
// babel-preset-taro 更多选项和默认值:
// https://github.com/NervJS/taro/blob/next/packages/babel-preset-taro/README.md
module.exports = {
presets: [
['taro', {
framework: 'vue3',
ts: false
}]
]
}
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
NutButton: typeof import('@nutui/nutui-taro')['Button']
NutCol: typeof import('@nutui/nutui-taro')['Col']
NutRow: typeof import('@nutui/nutui-taro')['Row']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}
module.exports = {
env: {
NODE_ENV: '"development"'
},
defineConstants: {
},
mini: {},
h5: {}
}
const path = require('path')
import ComponentsPlugin from 'unplugin-vue-components/webpack'
import NutUIResolver from '@nutui/nutui-taro/dist/resolver'
const config = {
projectName: 'custom_form',
date: '2023-3-23',
designWidth(input) {
if (input?.file?.replace(/\\+/g, '/').indexOf('@nutui') > -1) {
return 375
}
return 750
},
deviceRatio: {
640: 2.34 / 2,
750: 1,
828: 1.81 / 2,
375: 2 / 1,
},
alias: {
// 配置目录别名
'@/utils': path.resolve(__dirname, '../src/utils'),
'@/components': path.resolve(__dirname, '../src/components'),
'@/images': path.resolve(__dirname, '../src/assets/images'),
'@/assets': path.resolve(__dirname, '../src/assets'),
'@/composables': path.resolve(__dirname, '../src/composables'),
'@/api': path.resolve(__dirname, '../src/api'),
'@/stores': path.resolve(__dirname, '../src/stores'),
'@/hooks': path.resolve(__dirname, '../src/hooks'),
},
sourceRoot: 'src',
outputRoot: `dist/${process.env.TARO_ENV}`,
plugins: ['@tarojs/plugin-html'],
defineConstants: {},
copy: {
patterns: [],
options: {},
},
framework: 'vue3',
compiler: {
type: 'webpack5',
prebundle: { enable: false },
},
cache: {
enable: false, // Webpack 持久化缓存配置,建议开启。默认配置请参考:https://docs.taro.zone/docs/config-detail#cache
},
sass: {
data: `@import "@nutui/nutui-taro/dist/styles/variables.scss";`,
},
mini: {
webpackChain(chain) {
chain.plugin('unplugin-vue-components').use(
ComponentsPlugin({
resolvers: [NutUIResolver({ taro: true })],
}),
)
},
postcss: {
pxtransform: {
enable: true,
config: {
// selectorBlackList: ['nut-']
},
},
url: {
enable: true,
config: {
limit: 1024, // 设定转换尺寸上限
},
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]',
},
},
},
enableSourceMap: false
},
h5: {
webpackChain(chain) {
chain.plugin('unplugin-vue-components').use(
ComponentsPlugin({
resolvers: [NutUIResolver({ taro: true })],
}),
)
},
publicPath: '/',
staticDirectory: 'static',
esnextModules: ['nutui-taro', 'icons-vue-taro'],
postcss: {
autoprefixer: {
enable: true,
config: {},
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]',
},
},
},
},
}
module.exports = function (merge) {
if (process.env.NODE_ENV === 'development') {
return merge({}, config, require('./dev'))
}
return merge({}, config, require('./prod'))
}
module.exports = {
env: {
NODE_ENV: '"production"'
},
defineConstants: {
},
mini: {},
h5: {
/**
* WebpackChain 插件配置
* @docs https://github.com/neutrinojs/webpack-chain
*/
// webpackChain (chain) {
// /**
// * 如果 h5 端编译后体积过大,可以使用 webpack-bundle-analyzer 插件对打包体积进行分析。
// * @docs https://github.com/webpack-contrib/webpack-bundle-analyzer
// */
// chain.plugin('analyzer')
// .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
// /**
// * 如果 h5 端首屏加载时间过长,可以使用 prerender-spa-plugin 插件预加载首页。
// * @docs https://github.com/chrisvfritz/prerender-spa-plugin
// */
// const path = require('path')
// const Prerender = require('prerender-spa-plugin')
// const staticDir = path.join(__dirname, '..', 'dist')
// chain
// .plugin('prerender')
// .use(new Prerender({
// staticDir,
// routes: [ '/pages/index/index' ],
// postProcess: (context) => ({ ...context, outputPath: path.join(staticDir, 'index.html') })
// }))
// }
}
}
{
"name": "custom_form",
"version": "1.0.0",
"private": true,
"description": "自定义表单",
"templateInfo": {
"name": "vue3-NutUI4",
"typescript": false,
"css": "less"
},
"scripts": {
"build:weapp": "taro build --type weapp",
"build:swan": "taro build --type swan",
"build:alipay": "taro build --type alipay",
"build:tt": "taro build --type tt",
"build:h5": "taro build --type h5",
"build:rn": "taro build --type rn",
"build:qq": "taro build --type qq",
"build:jd": "taro build --type jd",
"build:quickapp": "taro build --type quickapp",
"dev:weapp": "npm run build:weapp -- --watch",
"dev:swan": "npm run build:swan -- --watch",
"dev:alipay": "npm run build:alipay -- --watch",
"dev:tt": "npm run build:tt -- --watch",
"dev:h5": "npm run build:h5 -- --watch",
"dev:rn": "npm run build:rn -- --watch",
"dev:qq": "npm run build:qq -- --watch",
"dev:jd": "npm run build:jd -- --watch",
"dev:quickapp": "npm run build:quickapp -- --watch"
},
"browserslist": [
"last 3 versions",
"Android >= 4.1",
"ios >= 8"
],
"author": "",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.7.7",
"@nutui/icons-vue-taro": "^0.0.9",
"@nutui/nutui-taro": "^4.0.0",
"@tarojs/components": "3.6.2",
"@tarojs/helper": "3.6.2",
"@tarojs/plugin-framework-vue3": "3.6.2",
"@tarojs/plugin-html": "3.6.2",
"@tarojs/plugin-platform-alipay": "3.6.2",
"@tarojs/plugin-platform-h5": "3.6.2",
"@tarojs/plugin-platform-jd": "3.6.2",
"@tarojs/plugin-platform-qq": "3.6.2",
"@tarojs/plugin-platform-swan": "3.6.2",
"@tarojs/plugin-platform-tt": "3.6.2",
"@tarojs/plugin-platform-weapp": "3.6.2",
"@tarojs/runtime": "3.6.2",
"@tarojs/shared": "3.6.2",
"@tarojs/taro": "3.6.2",
"dayjs": "^1.11.7",
"pinia": "^2.0.33",
"vue": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.8.0",
"@tarojs/cli": "3.6.2",
"@tarojs/webpack5-runner": "3.6.2",
"@types/webpack-env": "^1.13.6",
"@vue/babel-plugin-jsx": "^1.0.6",
"@vue/compiler-sfc": "^3.0.0",
"babel-preset-taro": "3.6.2",
"css-loader": "3.4.2",
"eslint": "^8.12.0",
"eslint-config-taro": "3.6.2",
"eslint-plugin-vue": "^8.0.0",
"style-loader": "1.3.0",
"stylelint": "9.3.0",
"unplugin-vue-components": "^0.23.0",
"vue-loader": "^17.0.0",
"webpack": "5.69.0"
}
}
{
"miniprogramRoot": "./dist",
"projectname": "custom_form",
"description": "自定义表单",
"appid": "touristappid",
"setting": {
"urlCheck": true,
"es6": false,
"enhance": false,
"compileHotReLoad": false,
"postcss": false,
"minified": false
},
"compileType": "miniprogram"
}
{
"miniprogramRoot": "./",
"projectname": "custom_form",
"description": "自定义表单",
"appid": "touristappid",
"setting": {
"urlCheck": true,
"es6": false,
"postcss": false,
"minified": false
},
"compileType": "miniprogram"
}
export default defineAppConfig({
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
})
/*
* @Date: 2023-03-23 11:17:54
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-03-23 13:47:12
* @FilePath: /custom_form/src/app.js
* @Description: 文件描述
*/
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './app.less'
const App = createApp({
onShow (options) {},
// 入口组件不需要实现 render 方法,即使实现了也会被 taro 所覆盖
})
App.use(createPinia())
export default App
File mode changed
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta content="width=device-width,initial-scale=1,user-scalable=no" name="viewport">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="format-detection" content="telephone=no,address=no">
<meta name="apple-mobile-web-app-status-bar-style" content="white">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" >
<title>custom_form</title>
<script><%= htmlWebpackPlugin.options.script %></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
export default definePageConfig({
navigationBarTitleText: '首页'
})
<template>
<view class="index">
<nut-row>
<nut-col :span="is_pc ? 22 : 24" :offset="is_pc ? 1 : 0">
<div style="background-color: red; color: white;">span:24</div>
</nut-col>
</nut-row>
</view>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { mainStore } from '@/stores'
import { wxInfo, getUrlParams } from "@/utils/tools";
import { computed, watchEffect, onMounted } from "vue";
// web端判断
const is_pc = computed(() => process.env.TARO_ENV === 'h5' && wxInfo().isPC);
const store = mainStore();
const { formInfo } = storeToRefs(store);
console.warn(is_pc.value);
</script>
<style lang="less">
</style>
/*
* @Date: 2022-04-18 15:59:42
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-03-23 13:19:21
* @FilePath: /custom_form/src/stores/index.js
* @Description: 文件描述
*/
import { defineStore } from 'pinia';
// import { testStore } from './test'; // 另一个store
export const mainStore = defineStore('main', {
state: () => {
return {
fieldName: '',
formInfo: {}, // 表单字段信息
formSetting: {}, // 表单数据收集设置
successInfo: {}, // 表单提交返回值
};
},
getters: {
getKeepPages () {
return this.keepPages
},
// getTestStoreList () {
// return testStore().list // 返回另一个store的值
// }
},
actions: {
changeFieldName (v) {
this.fieldName = v;
},
changeFormInfo (v) {
this.formInfo = v;
},
changeFormSetting (v) {
this.formSetting = v;
},
changeSuccessInfo (v) {
this.successInfo = v;
},
},
});
/*
* @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: 2022-12-01 16:33:51
* @FilePath: /data-table/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: 'custom_form',
};
/**
* @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 => {
return response;
},
error => {
return Promise.reject(error);
});
export default axios;
This diff is collapsed. Click to expand it.
/*
* @Date: 2022-07-18 10:22:22
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-08-22 18:23:07
* @FilePath: /front/src/utils/generateIcons.js
* @Description: 文件描述
*/
import icon_nav from '@images/icon/nav.png'
import icon_gz from '@images/icon/icon_gz.png'
export {
icon_nav,
icon_gz,
}
/*
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2022-05-17 11:17:58
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-07-18 10:42:12
* @FilePath: /front/src/utils/generateModules.js
* @Description:
*/
import MuiVideo from '@/components/MuiVideo/index.vue'
export {
MuiVideo,
}
/*
* @Date: 2022-05-17 11:26:03
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2022-08-05 15:18:06
* @FilePath: /front/src/utils/generatePackage.js
* @Description: 文件描述
*/
import Cookies from 'js-cookie'
import $ from 'jquery'
import _ from 'lodash'
import dayjs from 'dayjs'
import axios from '@/utils/axios';
import { storeToRefs } from 'pinia'
import { mainStore } from '@/store'
import { Toast, Dialog } from 'vant';
import { wxInfo, hasEllipsis } from '@/utils/tools';
import { useTitle } from '@vueuse/core'
export {
Cookies,
$,
_,
axios,
storeToRefs,
mainStore,
Toast,
Dialog,
wxInfo,
hasEllipsis,
useTitle,
dayjs
}
/*
* @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 sha1 from "js-sha1";
function getEtag(buffer, callback) {
// sha1算法
var shA1 = sha1.digest;
// 以4M为单位分割
var blockSize = 4 * 1024 * 1024;
var sha1String = [];
var prefix = 0x16;
var blockCount = 0;
var bufferSize = buffer.size || buffer.length || buffer.byteLength;
blockCount = Math.ceil(bufferSize / blockSize);
for (var i = 0; i < blockCount; i++) {
sha1String.push(shA1(buffer.slice(i * blockSize, (i + 1) * blockSize)));
}
function concatArr2Uint8(s) {//Array 2 Uint8Array
var tmp = [];
for (var i of s) tmp = tmp.concat(i);
return new Uint8Array(tmp);
}
function Uint8ToBase64(u8Arr, urisafe) {//Uint8Array 2 Base64
var CHUNK_SIZE = 0x8000; //arbitrary number
var index = 0;
var length = u8Arr.length;
var result = '';
var slice;
while (index < length) {
slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
result += String.fromCharCode.apply(null, slice);
index += CHUNK_SIZE;
}
return urisafe ? btoa(result).replace(/\//g, '_').replace(/\+/g, '-') : btoa(result);
}
function calcEtag() {
if (!sha1String.length) return 'Fto5o-5ea0sNMlW_75VgGJCv2AcJ';
var sha1Buffer = concatArr2Uint8(sha1String);
// 如果大于4M,则对各个块的sha1结果再次sha1
if (blockCount > 1) {
prefix = 0x96;
sha1Buffer = shA1(sha1Buffer.buffer);
} else {
sha1Buffer = Array.apply([], sha1Buffer);
}
sha1Buffer = concatArr2Uint8([[prefix], sha1Buffer]);
return Uint8ToBase64(sha1Buffer, true);
}
return (calcEtag());
}
export { getEtag }
This diff is collapsed. Click to expand it.
/*
* @Date: 2022-04-18 15:59:42
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2023-02-24 16:13:06
* @FilePath: /data-table/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 isMobile = u.indexOf('Android') > -1 || u.indexOf('iPhone') > -1 || u.indexOf('iPad') > -1; // 移动端平台
let isIpad = u.indexOf('iPad') > -1; // iPad平台
let uAgent = navigator.userAgent.toLowerCase();
let isWeiXin = (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,
isWeiXin,
isMobile,
isIpad,
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]] = decodeURIComponent(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
}
/**
* 自定义替换参数
* @param {*} url
* @param {*} arg
* @param {*} arg_val
* @returns
*/
const changeURLArg = (url, arg, arg_val) => {
var pattern = arg + '=([^&]*)';
var replaceText = arg + '=' + arg_val;
if (url.match(pattern)) {
var tmp = '/(' + arg + '=)([^&]*)/gi';
tmp = url.replace(eval(tmp), replaceText);
return tmp;
} else {
if (url.match('[\?]')) {
return url + '&' + replaceText;
} else {
return url + '?' + replaceText;
}
}
return url + '\n' + arg + '\n' + arg_val;
}
// 获取参数key/value值对
const getUrlParams = (url) => {
// 没有参数处理
if (url.split('?').length === 1) return false;
let arr = url.split('?');
let res = arr[1].split('&');
let items = {};
for (let i = 0; i < res.length; i++) {
let [key, value] = res[i].split('=');
items[key] = value;
}
return items
}
// 格式化URL参数为字符串
const stringifyQuery = (params) => {
const queryString = [];
Object.keys(params || {}).forEach((k) => {
queryString.push(k + '=' + params[k]);
});
return '?' + queryString.join('&');
};
export {
formatDate,
wxInfo,
hasEllipsis,
parseQueryString,
strExist,
changeURLArg,
getUrlParams,
stringifyQuery,
};
import VConsole from 'vconsole';
// const vConsole = new VConsole();
let vConsole = '';
// 或者使用配置参数来初始化,详情见文档
if (+import.meta.env.VITE_CONSOLE) {
vConsole = new VConsole({ theme: 'dark' });
}
export default vConsole
This diff could not be displayed because it is too large.