main
王文龙 2023-11-27 11:40:33 +08:00
commit 597b0922d7
135 changed files with 59060 additions and 0 deletions

91
.commitlintrc.js Executable file
View File

@ -0,0 +1,91 @@
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const scopes = fs
.readdirSync(path.resolve(__dirname, 'src'), { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name.replace(/s$/, ''));
// precomputed scope
const scopeComplete = execSync('git status --porcelain || true')
.toString()
.trim()
.split('\n')
.find((r) => ~r.indexOf('M src'))
?.replace(/(\/)/g, '%%')
?.match(/src%%((\w|-)*)/)?.[1]
?.replace(/s$/, '');
/** @type {import('cz-git').UserConfig} */
module.exports = {
ignores: [(commit) => commit.includes('init')],
extends: ['@commitlint/config-conventional'],
rules: {
'body-leading-blank': [2, 'always'],
'footer-leading-blank': [1, 'always'],
'header-max-length': [2, 'always', 108],
'subject-empty': [2, 'never'],
'type-empty': [2, 'never'],
'subject-case': [0],
'type-enum': [
2,
'always',
['feat', 'fix', 'perf', 'style', 'docs', 'test', 'refactor', 'build', 'ci', 'chore', 'revert', 'wip', 'workflow', 'types', 'release'],
],
},
prompt: {
/** @use `yarn commit :f` */
alias: {
f: 'docs: fix typos',
r: 'docs: update README',
s: 'style: update code format',
b: 'build: bump dependencies',
c: 'chore: update config',
},
customScopesAlign: !scopeComplete ? 'top' : 'bottom',
defaultScope: scopeComplete,
scopes: [...scopes, 'mock'],
allowEmptyIssuePrefixs: false,
allowCustomIssuePrefixs: false,
// English
typesAppend: [
{ value: 'wip', name: 'wip: work in process' },
{ value: 'workflow', name: 'workflow: workflow improvements' },
{ value: 'types', name: 'types: type definition file changes' },
],
// 中英文对照版
// messages: {
// type: '选择你要提交的类型 :',
// scope: '选择一个提交范围 (可选):',
// customScope: '请输入自定义的提交范围 :',
// subject: '填写简短精炼的变更描述 :\n',
// body: '填写更加详细的变更描述 (可选)。使用 "|" 换行 :\n',
// breaking: '列举非兼容性重大的变更 (可选)。使用 "|" 换行 :\n',
// footerPrefixsSelect: '选择关联issue前缀 (可选):',
// customFooterPrefixs: '输入自定义issue前缀 :',
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
// confirmCommit: '是否提交或修改commit ?',
// },
// types: [
// { value: 'feat', name: 'feat: 新增功能' },
// { value: 'fix', name: 'fix: 修复缺陷' },
// { value: 'docs', name: 'docs: 文档变更' },
// { value: 'style', name: 'style: 代码格式' },
// { value: 'refactor', name: 'refactor: 代码重构' },
// { value: 'perf', name: 'perf: 性能优化' },
// { value: 'test', name: 'test: 添加疏漏测试或已有测试改动' },
// { value: 'build', name: 'build: 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)' },
// { value: 'ci', name: 'ci: 修改 CI 配置、脚本' },
// { value: 'revert', name: 'revert: 回滚 commit' },
// { value: 'chore', name: 'chore: 对构建过程或辅助工具和库的更改 (不影响源文件、测试用例)' },
// { value: 'wip', name: 'wip: 正在开发中' },
// { value: 'workflow', name: 'workflow: 工作流程改进' },
// { value: 'types', name: 'types: 类型定义文件修改' },
// ],
// emptyScopesAlias: 'empty: 不填写',
// customScopesAlias: 'custom: 自定义',
},
};

9
.env Executable file
View File

@ -0,0 +1,9 @@
VITE_TOKEN_KEY=tokenKey
VITE_URL_PREFIX=/api
# VITE_BASE_APP_ID='wx0fd5e237dba24ff4'
VITE_BASE_APP_ID='wxbad2e8a91c62a734'
# VITE_BASE_APP_SECRET='14f1027251416b49734c36bf58d6a741'
VITE_BASE_APP_SECRET='e1b7fc425ca9cca05dd83609a6dc9c00'

9
.env.development Executable file
View File

@ -0,0 +1,9 @@
VITE_USE_MOCK=false
VITE_USE_ERUDA=false
VITE_USE_COMPRESS=false
VITE_USE_REPORT=false
VITE_BASE_API_URL='http://139.224.10.234:8088'

9
.env.production Executable file
View File

@ -0,0 +1,9 @@
VITE_USE_MOCK=false
VITE_USE_ERUDA=false
VITE_USE_COMPRESS=true
VITE_USE_REPORT=false
VITE_BASE_API_URL='/'

7
.env.test Executable file
View File

@ -0,0 +1,7 @@
VITE_USE_MOCK=true
VITE_USE_ERUDA=true
VITE_USE_COMPRESS=true
VITE_USE_REPORT=false

15
.eslintignore Executable file
View File

@ -0,0 +1,15 @@
*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile

80
.eslintrc-auto-import.json Executable file
View File

@ -0,0 +1,80 @@
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"EffectScope": true,
"InjectionKey": true,
"PropType": true,
"Ref": true,
"VNode": true,
"acceptHMRUpdate": true,
"computed": true,
"createApp": true,
"createPinia": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"defineStore": true,
"effectScope": true,
"getActivePinia": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"mapActions": true,
"mapGetters": true,
"mapState": true,
"mapStores": true,
"mapWritableState": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"setActivePinia": true,
"setMapStoreSuffix": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"storeToRefs": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useLink": true,
"useRoute": true,
"useRouter": true,
"useSlots": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true,
"toValue": true
}
}

77
.eslintrc.js Executable file
View File

@ -0,0 +1,77 @@
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
project: './tsconfig.*?.json',
createDefaultProgram: false,
extraFileExtensions: ['.vue'],
},
extends: ['plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
plugins: ['vue', '@typescript-eslint', 'import'],
rules: {
'no-unused-vars': 'off',
'no-case-declarations': 'off',
'no-use-before-define': 'off',
'space-before-function-paren': 'off',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'vue/script-setup-uses-vars': 'error',
'vue/no-reserved-component-names': 'off',
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/require-default-prop': 'off',
'vue/require-explicit-emits': 'off',
'vue/html-self-closing': [
'error',
{
html: {
void: 'always',
normal: 'never',
component: 'always',
},
svg: 'always',
math: 'always',
},
],
'vue/multi-word-component-names': 'off',
},
globals: { defineOptions: 'readonly' },
};

25
.gitignore vendored Executable file
View File

@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
.eslintcache
# Editor directories and files
!.vscode/extensions.json
.idea
.fleet
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

8
.husky/commit-msg Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
PATH="/usr/local/bin:$PATH"
npx --no-install commitlint --edit "$1"

7
.husky/pre-commit Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
[ -n "$CI" ] && exit 0
# Format and submit code according to lintstagedrc.js configuration
npm run lint:lint-staged

9
.prettierignore Executable file
View File

@ -0,0 +1,9 @@
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*

3
.stylelintignore Executable file
View File

@ -0,0 +1,3 @@
/dist/*
/public/*
public/*

6
Dockerfile Executable file
View File

@ -0,0 +1,6 @@
FROM nginx
# 将dist文件中的内容复制到 /usr/share/nginx/html/ 这个目录下面
COPY dist/ /usr/share/nginx/html/dist/
# 用本地的 nginx.conf 配置来替换nginx镜像里的默认配置
COPY nginx.conf /etc/nginx/nginx.conf

44
admin.conf Executable file
View File

@ -0,0 +1,44 @@
server {
listen 4399;
server_name admin.swfc.store;
gzip on;
# 定义要压缩的文件类型
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# 定义压缩级别
gzip_comp_level 6;
# 定义压缩缓冲区大小
gzip_buffers 16 8k;
# 定义压缩最小文件大小
gzip_min_length 256;
# 定义压缩的 HTTP 版本
gzip_http_version 1.1;
# 定义压缩的条件
gzip_vary on;
# 定义压缩的处理方式
gzip_proxied any;
# 定义压缩的处理方法
gzip_static on;
root /usr/share/nginx/html/admin/dist;
location / {
index index.html index.htm;
# try_files $uri $uri/ @router;
}
location @router {
rewrite ^.*$ /index.html break;
}
location /api{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 20M;
proxy_send_timeout 500;
proxy_read_timeout 480;
rewrite ^/api(.*)$ $1 break;
proxy_pass http://localhost:8088;
}
}

7
build/constant.ts Executable file
View File

@ -0,0 +1,7 @@
export const API_BASE_URL = '';
export const MOCK_API_BASE_URL = '';
export const API_TARGET_URL = '';
export const MOCK_API_TARGET_URL = '';

27
build/utils.ts Executable file
View File

@ -0,0 +1,27 @@
// Read all environment variable configuration files to process.env
export function wrapperEnv(envConf: Recordable): ViteEnv {
const ret: any = {};
for (const envName of Object.keys(envConf)) {
let realName = envConf[envName].replace(/\\n/g, '\n');
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
if (envName === 'VITE_PORT') {
realName = Number(realName);
}
if (envName === 'VITE_PROXY' && realName) {
try {
realName = JSON.parse(realName.replace(/'/g, '"'));
} catch (error) {
realName = '';
}
}
ret[envName] = realName;
if (typeof realName === 'string') {
process.env[envName] = realName;
} else if (typeof realName === 'object') {
process.env[envName] = JSON.stringify(realName);
}
}
return ret;
}

View File

@ -0,0 +1,25 @@
/**
* @name AutoImportDeps
* @description
*/
import AutoImport from 'unplugin-auto-import/vite';
import { VarletUIResolver, VantResolver } from 'unplugin-vue-components/resolvers';
export const AutoImportDeps = () => {
return AutoImport({
dts: 'types/auto-imports.d.ts',
imports: [
'vue',
'pinia',
'vue-router',
{
'@vueuse/core': [],
},
],
eslintrc: {
enabled: true,
},
resolvers: [VarletUIResolver(), VantResolver()],
});
};

35
build/vite/plugins/component.ts Executable file
View File

@ -0,0 +1,35 @@
/**
* @name AutoRegistryComponents
* @description
*/
import Components from 'unplugin-vue-components/vite';
import { VueUseComponentsResolver, VantResolver, VarletUIResolver } from 'unplugin-vue-components/resolvers';
const NutUIResolver = () => {
return (name) => {
if (name.startsWith('Nut')) {
const partialName = name.slice(3);
return {
name: partialName,
from: '@nutui/nutui',
sideEffects: `@nutui/nutui/dist/packages/${partialName.toLowerCase()}/style`,
};
}
};
};
export const AutoRegistryComponents = () => {
return Components({
// dirs: ['src/components'],
extensions: ['vue', 'md'],
deep: true,
dts: 'types/components.d.ts',
directoryAsNamespace: false,
globalNamespaces: [],
directives: true,
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
resolvers: [VueUseComponentsResolver(), VantResolver(), VarletUIResolver(), NutUIResolver()],
});
};

19
build/vite/plugins/compress.ts Executable file
View File

@ -0,0 +1,19 @@
/**
* @name ConfigCompressPlugin
* @description .gz
*/
import viteCompression from 'vite-plugin-compression';
export const ConfigCompressPlugin = () => {
return viteCompression({
verbose: true, // 默认即可
disable: false, //开启压缩(不禁用),默认即可
deleteOriginFile: false, //删除源文件
threshold: 10240, //压缩前最小文件大小
algorithm: 'gzip', //压缩算法
ext: '.gz', //文件类型
});
return [];
};

10
build/vite/plugins/eruda.ts Executable file
View File

@ -0,0 +1,10 @@
/**
* @name ConfigEruda
* @description 便
*/
import eruda from 'vite-plugin-eruda';
export const ConfigEruda = () => {
return eruda();
};

37
build/vite/plugins/imagemin.ts Executable file
View File

@ -0,0 +1,37 @@
/**
* @name ConfigImageminPlugin
* @description
*/
import viteImagemin from 'vite-plugin-imagemin';
export function ConfigImageminPlugin() {
const plugin = viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false,
},
mozjpeg: {
quality: 20,
},
optipng: {
optimizationLevel: 7,
},
pngquant: {
quality: [0.8, 0.9],
speed: 4,
},
svgo: {
plugins: [
{
name: 'removeViewBox',
},
{
name: 'removeEmptyAttrs',
active: false,
},
],
},
});
return plugin;
}

78
build/vite/plugins/index.ts Executable file
View File

@ -0,0 +1,78 @@
/**
* @name createVitePlugins
* @description plugins
*/
import type { PluginOption } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import vueSetupExtend from 'vite-plugin-vue-setup-extend-plus';
import { ConfigSvgIconsPlugin } from './svgIcons';
import { AutoRegistryComponents } from './component';
import { AutoImportDeps } from './autoImport';
import { ConfigMockPlugin } from './mock';
import { ConfigCompressPlugin } from './compress';
import { ConfigPagesPlugin } from './pages';
import { ConfigRestartPlugin } from './restart';
import { ConfigProgressPlugin } from './progress';
import { ConfigEruda } from './eruda';
import { ConfigImageminPlugin } from './imagemin';
import { ConfigVisualizerConfig } from './visualizer';
import Unocss from 'unocss/vite';
import { presetUno } from 'unocss';
export function createVitePlugins(env: ViteEnv, isBuild: boolean) {
const { VITE_USE_MOCK, VITE_USE_ERUDA, VITE_USE_COMPRESS, VITE_USE_REPORT } = env;
const vitePlugins: (PluginOption | PluginOption[])[] = [
// vue支持
vue(),
// JSX支持
vueJsx(),
// setup语法糖组件名支持
vueSetupExtend(),
];
// 自动按需引入组件
vitePlugins.push(AutoRegistryComponents());
// 自动按需引入依赖
vitePlugins.push(AutoImportDeps());
// 自动生成路由
vitePlugins.push(ConfigPagesPlugin());
// 监听配置文件改动重启
vitePlugins.push(ConfigRestartPlugin());
// 构建时显示进度条
vitePlugins.push(ConfigProgressPlugin());
// eruda
VITE_USE_ERUDA && vitePlugins.push(ConfigEruda());
// rollup-plugin-visualizer
VITE_USE_REPORT && vitePlugins.push(ConfigVisualizerConfig());
// vite-plugin-mock
VITE_USE_MOCK && vitePlugins.push(ConfigMockPlugin(isBuild));
// vite-plugin-svg-icons
vitePlugins.push(ConfigSvgIconsPlugin(isBuild));
vitePlugins.push(
Unocss({
presets: [presetUno()],
}),
);
if (isBuild) {
// vite-plugin-imagemin
vitePlugins.push(ConfigImageminPlugin());
// 开启.gz压缩 rollup-plugin-gzip
VITE_USE_COMPRESS && vitePlugins.push(ConfigCompressPlugin());
}
return vitePlugins;
}

19
build/vite/plugins/mock.ts Executable file
View File

@ -0,0 +1,19 @@
/**
* @name ConfigMockPlugin
* @description mockjs
*/
import { viteMockServe } from 'vite-plugin-mock';
export const ConfigMockPlugin = (isBuild: boolean) => {
return viteMockServe({
ignore: /^\_/,
mockPath: 'mock',
localEnabled: !isBuild,
prodEnabled: false, //实际开发请关闭,会影响打包体积
// https://github.com/anncwb/vite-plugin-mock/issues/9
injectCode: `
import { setupProdMockServer } from '../mock/_createProdMockServer';
setupProdMockServer();
`,
});
};

14
build/vite/plugins/pages.ts Executable file
View File

@ -0,0 +1,14 @@
/**
* @name ConfigPagesPlugin
* @description
*/
import Pages from 'vite-plugin-pages';
export const ConfigPagesPlugin = () => {
return Pages({
pagesDir: [{ dir: 'src/pages', baseRoute: '' }],
extensions: ['vue', 'md'],
exclude: ['**/components/*.vue'],
nuxtStyle: true,
});
};

11
build/vite/plugins/progress.ts Executable file
View File

@ -0,0 +1,11 @@
/**
* @name ConfigProgressPlugin
* @description
*/
import { Plugin } from 'vite';
import progress from 'vite-plugin-progress';
export const ConfigProgressPlugin = () => {
return progress() as Plugin;
};

12
build/vite/plugins/restart.ts Executable file
View File

@ -0,0 +1,12 @@
/**
* @name ConfigRestartPlugin
* @description Vite
*/
import ViteRestart from 'vite-plugin-restart';
export const ConfigRestartPlugin = () => {
return ViteRestart({
restart: ['*.config.[jt]s', '**/config/*.[jt]s'],
});
};

17
build/vite/plugins/svgIcons.ts Executable file
View File

@ -0,0 +1,17 @@
/**
* @name SvgIconsPlugin
* @description SVG
*/
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
import path from 'path';
export const ConfigSvgIconsPlugin = (isBuild: boolean) => {
return createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
svgoOptions: isBuild,
});
};

View File

@ -0,0 +1,15 @@
/**
* @name ConfigVisualizerConfig
* @description
*/
import visualizer from 'rollup-plugin-visualizer';
export function ConfigVisualizerConfig() {
return visualizer({
filename: './node_modules/.cache/visualizer/stats.html',
open: true,
gzipSize: true,
brotliSize: true,
}) as Plugin;
}

20
build/vite/proxy.ts Executable file
View File

@ -0,0 +1,20 @@
import { API_BASE_URL, API_TARGET_URL, MOCK_API_BASE_URL, MOCK_API_TARGET_URL } from '../constant';
import { ProxyOptions } from 'vite';
type ProxyTargetList = Record<string, ProxyOptions>;
const init: ProxyTargetList = {
// test
[API_BASE_URL]: {
target: API_TARGET_URL,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${API_BASE_URL}`), ''),
},
// mock
[MOCK_API_BASE_URL]: {
target: MOCK_API_TARGET_URL,
changeOrigin: true,
rewrite: (path) => path.replace(new RegExp(`^${MOCK_API_BASE_URL}`), '/api'),
},
};
export default init;

44
h5.conf Executable file
View File

@ -0,0 +1,44 @@
server {
listen 80;
server_name swfc.store;
gzip on;
# 定义要压缩的文件类型
gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# 定义压缩级别
gzip_comp_level 6;
# 定义压缩缓冲区大小
gzip_buffers 16 8k;
# 定义压缩最小文件大小
gzip_min_length 256;
# 定义压缩的 HTTP 版本
gzip_http_version 1.1;
# 定义压缩的条件
gzip_vary on;
# 定义压缩的处理方式
gzip_proxied any;
# 定义压缩的处理方法
gzip_static on;
root /usr/share/nginx/html/h5/dist;
location / {
index index.html index.htm;
try_files $uri $uri/ @router;
}
location @router {
rewrite ^.*$ /index.html break;
}
location /api{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 20M;
proxy_send_timeout 500;
proxy_read_timeout 480;
rewrite ^/api(.*)$ $1 break;
proxy_pass http://localhost:8088;
}
}

82
index copy.html Executable file
View File

@ -0,0 +1,82 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<meta name="format-detection" content="telephone=no, email=no, date=no, address=no" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<script src="//res2.wx.qq.com/open/js/jweixin-1.6.0.js" type="text/javascript"></script>
<!-- <script src="wechatH5Video.min.js" type="text/javascript"></script> -->
<title>上海环球金融中心</title>
</head>
<body>
<div id="videoWrapper"></div>
<div id="app"> </div>
<script type="module" src="/src/main.ts"></script>
<script>
window.onload = function () {
// if ( window.sessionStorage.getItem('isFirst') !== 'false') {
// var source = '//huanqiuzhongxin.oss-cn-shanghai.aliyuncs.com/shipin/second.mp4';
// var video = new wechatH5Video(source, {
// context: 'videoWrapper',
// mask: false,
// poster:
// 'https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1541401188&di=41264a717eb6a592709efc04a66e216d&src=http://i8.download.fd.pchome.net/t_600x1024/g1/M00/07/04/oYYBAFMioPmIClVuAALr2NPIYaIAABZ9QKPJJUAAuvw540.jpg',
// playBtn: true,
// jumpBtn: false,
// autoClose: true,
// canvas: false,
// isRotate: true,
// onPlay() {
// },
// onPause() {
// },
// onEnd() {
// window.sessionStorage.setItem('isFirst', 'false');
// // console.log('end');
// },
// });
// video.load();
// setTimeout(() => {
// video.play();
// }, 50);
// }
document.addEventListener('touchstart', function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
var lastTouchEnd = 0;
document.addEventListener(
'touchend',
function (event) {
var now = new Date().getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
},
false,
);
document.addEventListener('gesturestart', function (event) {
event.preventDefault();
});
};
</script>
<!-- <script src="https://cdn.bootcss.com/eruda/1.5.4/eruda.min.js"></script>
<script>
eruda.init();
</script> -->
</body>
</html>

51
index.html Executable file
View File

@ -0,0 +1,51 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<meta name="format-detection" content="telephone=no, email=no, date=no, address=no" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<script src="//res2.wx.qq.com/open/js/jweixin-1.6.0.js" type="text/javascript"></script>
<script src="wechatH5Video.min.js" type="text/javascript"></script>
<title>上海环球金融中心</title>
</head>
<body>
<div id="videoWrapper"></div>
<div id="app"> </div>
<script type="module" src="/src/main.ts"></script>
<script>
window.onload = function () {
document.addEventListener('touchstart', function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
var lastTouchEnd = 0;
document.addEventListener(
'touchend',
function (event) {
var now = new Date().getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
},
false,
);
document.addEventListener('gesturestart', function (event) {
event.preventDefault();
});
};
</script>
</body>
</html>

22
mock/index.ts Executable file
View File

@ -0,0 +1,22 @@
import { MockMethod, Recordable } from 'vite-plugin-mock';
interface response {
body: Recordable;
query: Recordable;
}
export default [
{
url: '/api/login',
method: 'post',
response: ({ body, query }: response) => {
console.log('body>>>>>>>>', body);
console.log('query>>>>>>>>', query);
return {
code: 200,
message: 'ok',
data: { name: 'Evan', age: 26 },
};
},
},
] as MockMethod[];

34278
package-lock.json generated Executable file

File diff suppressed because it is too large Load Diff

138
package.json Executable file
View File

@ -0,0 +1,138 @@
{
"name": "shop-h5",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged",
"prepare": "husky install",
"deps": "yarn upgrade-interactive --latest",
"commit": "git add . && git-cz"
},
"dependencies": {
"@nutui/icons-vue": "^0.1.1",
"@nutui/nutui": "^4.2.1",
"@samrahnama/triple-state-slider": "^1.1.10",
"@varlet/ui": "^2.13.0",
"@vueuse/core": "10.2.1",
"@vueuse/integrations": "10.2.1",
"axios": "1.4.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.9",
"mitt": "^3.0.1",
"pinia": "^2.1.3",
"pinia-plugin-persistedstate": "^3.1.0",
"quarkd": "^1.0.70",
"universal-cookie": "^4.0.4",
"unocss": "^0.57.4",
"vant": "^4.6.2",
"vue": "^3.3.1",
"vue-i18n": "^9.2.2",
"vue-router": "^4.2.4"
},
"devDependencies": {
"@commitlint/cli": "^17.6.6",
"@commitlint/config-conventional": "^17.6.6",
"@vitejs/plugin-basic-ssl": "^1.0.1",
"@vitejs/plugin-legacy": "^4.1.0",
"@vitejs/plugin-vue": "^4.2.3",
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/test-utils": "^2.4.0",
"@vue/tsconfig": "^0.4.0",
"amfe-flexible": "^2.2.1",
"autoprefixer": "^10.4.14",
"cnjm-postcss-px-to-viewport": "^1.0.0",
"consola": "^3.2.3",
"cross-env": "^7.0.3",
"cz-git": "^1.7.0",
"czg": "^1.7.0",
"eruda": "^3.0.0",
"eslint": "^8.45.0",
"eslint-config-prettier": "^8.8.0",
"eslint-define-config": "^1.21.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-vue": "^9.15.1",
"git-cz": "^4.9.0",
"husky": "8.0.3",
"jsdom": "^22.1.0",
"lint-staged": "13.2.3",
"mockjs": "^1.1.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.26",
"postcss-html": "1.5.0",
"postcss-less": "^6.0.0",
"prettier": "^3.0.0",
"rollup-plugin-visualizer": "^5.9.1",
"stylelint": "^15.10.1",
"stylelint-config-property-sort-order-smacss": "^9.1.0",
"stylelint-config-recommended": "^13.0.0",
"stylelint-config-recommended-vue": "^1.5.0",
"stylelint-config-standard": "^34.0.0",
"stylelint-config-standard-scss": "^10.0.0",
"stylelint-order": "^6.0.3",
"stylelint-prettier": "^4.0.0",
"terser": "^5.19.0",
"typescript": "^5.1.6",
"unplugin-auto-import": "^0.16.6",
"unplugin-vue-components": "^0.25.1",
"vite": "^4.4.4",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eruda": "^1.0.1",
"vite-plugin-imagemin": "^0.6.1",
"vite-plugin-mock": "^3.0.0",
"vite-plugin-pages": "^0.31.0",
"vite-plugin-progress": "^0.0.7",
"vite-plugin-restart": "^0.3.1",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue-setup-extend-plus": "^0.1.0",
"vitest": "^0.33.0",
"vue-eslint-parser": "^9.3.1",
"vue-tsc": "^1.8.5"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"resolutions": {
"bin-wrapper": "npm:bin-wrapper-china",
"gifsicle": "5.2.0"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
"prettier --write--parser json"
],
"package.json": [
"prettier --write"
],
"*.vue": [
"eslint --fix",
"prettier --write",
"stylelint --fix"
],
"*.{scss,less,styl,html}": [
"stylelint --fix",
"prettier --write"
],
"*.md": [
"prettier --write"
]
},
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
}
}

11572
pnpm-lock.yaml Executable file

File diff suppressed because it is too large Load Diff

33
postcss.config.js Executable file
View File

@ -0,0 +1,33 @@
const path = require('path')
const judgeComponent = (file) => {
const ignore = ['vant', '@nutui', '@varlet']
return ignore.some((item) => path.join(file).includes(path.join('node_modules', item)))
}
module.exports = {
plugins: {
autoprefixer: { overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8'] },
'cnjm-postcss-px-to-viewport': {
unitToConvert: 'px', // 要转化的单位
viewportWidth: 750, // UI设计稿的宽度
unitPrecision: 6, // 转换后的精度,即小数点位数
propList: ['*'], // 指定转换的css属性的单位*代表全部css属性的单位都进行转换
viewportUnit: 'vw', // 指定需要转换成的视窗单位默认vw
fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位默认vw
minPixelValue: 1, // 默认值1小于或等于1px则不进行转换
mediaQuery: true, // 是否在媒体查询的css代码中也进行转换默认false
replace: true, // 是否转换后直接更换属性值
landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'rem', //横屏时使用的单位
landscapeWidth: 1134, //横屏时使用的视口宽度
include: [],
exclude: [], // 设置忽略文件,用正则做目录名匹配
customFun: ({ file }) => {
// 这个自定义的方法是针对处理vant组件下的设计稿为375问题
const designWidth = judgeComponent(file) ? 375 : 750
return designWidth
},
},
},
}

18
prettier.config.js Executable file
View File

@ -0,0 +1,18 @@
module.exports = {
printWidth: 140,
semi: true,
vueIndentScriptAndStyle: true,
singleQuote: true,
trailingComma: 'all',
proseWrap: 'never',
htmlWhitespaceSensitivity: 'strict',
endOfLine: 'auto',
overrides: [
{
files: '.*rc',
options: {
parser: 'json',
},
},
],
};

1
public/wechatH5Video.min.js vendored Normal file

File diff suppressed because one or more lines are too long

36
src/App.vue Executable file
View File

@ -0,0 +1,36 @@
<template>
<div class="w-screen h-screen overflow-scroll">
<router-view />
</div>
</template>
<script setup lang="ts">
// document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
// // API
// WeixinJSBridge.call('hideToolbar');
// });
</script>
<style lang="scss">
#app {
font-family: 'Fontquan-XinYiJiXiangSong', Arial, Helvetica, sans-serif;
// color: rgba(255, 240, 215, 0.8);
color: #ffdfbd;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
height: 100vh;
overflow-y: auto;
}
.main {
background: url('@/assets/imgs/background.png');
// background-size: cover;
}
.bgi-light {
// background: url('@/assets/imgs/build.png') no-repeat;
background: url('https://huanqiuzhongxin.oss-cn-shanghai.aliyuncs.com/shipin/build.png') no-repeat;
background-size: cover;
}
.bg-lou {
background: url('@/assets/imgs/shop-detail/kuangs@2x.png') no-repeat;
background-size: cover;
}
</style>

137
src/api/index.ts Executable file
View File

@ -0,0 +1,137 @@
import { enc, SHA1 } from 'crypto-js';
import { http } from '@/utils/request';
// import { generateSignature } from '@/utils/util';
/**
*
* @returns UseAxiosReturn
*/
export function loginPassword() {
return http.post(`/login`, {
data: { name: '123' },
});
}
export function getWxMpRequest(params: any) {
return http.get(`/wx/wxlogin`, {
params,
});
}
export function getWxMpJsToken(params: any) {
return http.get(`/wx/access`, {
params,
});
}
export async function getWx({ token = localStorage.getItem('token'), url = window.location.href }: any) {
const res = await http.get('/weixin/cgi-bin/ticket/getticke', {
params: {
access_token: token,
type: 'jsapi',
},
});
// 生成nonceStr
const nonceStr = Math.random().toString(36).substring(2, 15);
// 获取timestamp当前时间戳
const timestamp = Math.floor(Date.now() / 1000);
// 根据需要的配置参数生成signature
const signature = SHA1(`noncestr=${nonceStr}&timestamp=${timestamp}&url=${url}`).toString(enc.Hex);
return {
result: {
timestamp,
nonceStr,
signature,
jsapi_ticket: res?.data?.ticket,
},
};
// return http.get(`/sns/oauth2/access_token`, {
// params: {
// code,
// grant_type: 'authorization_code',
// appid: import.meta.env.VITE_BASE_APP_ID,
// secret: import.meta.env.VITE_BASE_APP_SECRET,
// },
// });
}
/**
*
* @param query .
* @returns .
*/
export function queryShopPage(params?: any): Promise<any> {
return http.get('/buiness/shop/query/page', { params });
}
/**
*
* @param query .
* @returns .
*/
export function queryShopDetail(params?: any): Promise<any> {
return http.get('/buiness/shop', { params });
}
/**
* bx
* @param query .
* @returns .
*/
export function queryBoxPage(params?: any): Promise<any> {
return http.get('/buiness/box/query/page', { params });
}
/**
* bx
* @param query .
* @returns .
*/
export function queryBoxDetail(params?: any): Promise<any> {
return http.get('/buiness/box', { params });
}
/**
*
* @param query .
* @returns .
*/
export function queryHour(params?: any): Promise<any> {
return http.get('/buiness/shop/getHour', { params });
}
/**
*
* @param query .
* @returns .
*/
export function querySeason(params?: any): Promise<any> {
return http.get('/buiness/shop/getSeason', { params });
}
/**
*
* @param query .
* @returns .
*/
export function queryCoupon(params?: any): Promise<any> {
return http.get('/buiness/coupon/query/page', { params });
}
/**
*
* @param query .
* @returns .
*/
export function queryCouponLog(params?: any): Promise<any> {
return http.get('/buiness/coupon/getCoupon', { params });
}
/**
*
* @param query .
* @returns .
*/
export function queryVerification(params?: any): Promise<any> {
return http.get('/buiness/coupon/verification', { params });
}

17
src/assets/app.css Executable file
View File

@ -0,0 +1,17 @@
html,
body,
h1,
h2,
h3,
h4,
h5,
h6,
p {
margin: 0;
padding: 0;
}
html,
body {
scroll-behavior: auto;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

10
src/assets/font/index.css Executable file
View File

@ -0,0 +1,10 @@
@font-face {
font-family: 'Fontquan-XinYiJiXiangSong';
src:
url('Fontquan-XinYiJiXiangSong-Regular.woff2') format('woff2'),
url('Fontquan-XinYiJiXiangSong-Regular.woff') format('woff');
/* url('https://huanqiuzhongxin.oss-cn-shanghai.aliyuncs.com/ziti/font.ttf'); */
font-weight: normal;
font-style: normal;
font-display: swap;
}

BIN
src/assets/imgs/ail@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
src/assets/imgs/bgo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

BIN
src/assets/imgs/bgo@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
src/assets/imgs/build-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/imgs/build.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 MiB

BIN
src/assets/imgs/build.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
src/assets/imgs/dongj1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/imgs/dongj2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/assets/imgs/dtitle@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
src/assets/imgs/jijie1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
src/assets/imgs/jijie2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
src/assets/imgs/sale/cha@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
src/assets/imgs/sale/fenx@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
src/assets/imgs/sale/fulyh.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
src/assets/imgs/sale/hexiao.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/assets/imgs/sale/huod1@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/assets/imgs/sale/huod2@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
src/assets/imgs/sale/jint@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
src/assets/imgs/sale/lihe@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

BIN
src/assets/imgs/sale/lingwan.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
src/assets/imgs/sale/logohj.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
src/assets/imgs/sale/qbeij.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
src/assets/imgs/sale/tbj.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
src/assets/imgs/shiz.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 KiB

BIN
src/assets/imgs/swfcdp@2x.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
src/assets/imgs/title.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 KiB

BIN
src/assets/imgs/title.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
src/assets/imgs/tuij1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

BIN
src/assets/imgs/tuj2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
src/assets/imgs/xians2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
src/assets/imgs/xinshi1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More