update
This commit is contained in:
commit
8979172976
3
.browserslistrc
Normal file
3
.browserslistrc
Normal file
@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
23
.env.development
Normal file
23
.env.development
Normal file
@ -0,0 +1,23 @@
|
||||
# 只在开发模式中被载入
|
||||
|
||||
# 网站前缀
|
||||
VITE_BASE_URL = /
|
||||
|
||||
VITE__APP_VERSION__ = ''
|
||||
|
||||
# base api
|
||||
|
||||
VITE_BASE_API_VERSION = '1.0.001'
|
||||
|
||||
VITE_BASE_API_go = 'https://health.ufutx.com/go/api'
|
||||
|
||||
VITE_BASE_API = '//health.ufutx.net/api'
|
||||
|
||||
# 是否兼容旧的浏览器
|
||||
VITE_LEGACY = false
|
||||
|
||||
# mock api
|
||||
VITE_MOCK_API = '/mock-api/'
|
||||
|
||||
# 是否删除console
|
||||
VITE_DROP_CONSOLE = false
|
||||
22
.env.production
Normal file
22
.env.production
Normal file
@ -0,0 +1,22 @@
|
||||
# 只在开发模式中被载入
|
||||
|
||||
# 网站前缀
|
||||
VITE_BASE_URL = /h5/
|
||||
|
||||
VITE__APP_VERSION__ = ''
|
||||
|
||||
# base api
|
||||
|
||||
VITE_BASE_API_VERSION = '1.0.001'
|
||||
|
||||
VITE_BASE_API_go = '//health.ufutx.com/go/api'
|
||||
|
||||
VITE_BASE_API = '//health.ufutx.com/api'
|
||||
|
||||
# 是否兼容旧的浏览器
|
||||
VITE_LEGACY = false
|
||||
|
||||
# mock api
|
||||
VITE_MOCK_API = '/mock-api/'
|
||||
# 是否删除console
|
||||
VITE_DROP_CONSOLE = true
|
||||
16
.eslintignore
Normal file
16
.eslintignore
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
*.sh
|
||||
node_modules
|
||||
*.md
|
||||
*.woff
|
||||
*.ttf
|
||||
.vscode
|
||||
.idea
|
||||
dist
|
||||
/public
|
||||
/docs
|
||||
.husky
|
||||
.local
|
||||
/bin
|
||||
/src/mock
|
||||
Dockerfile
|
||||
108
.eslintrc.js
Normal file
108
.eslintrc.js
Normal file
@ -0,0 +1,108 @@
|
||||
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,
|
||||
tsx: true,
|
||||
},
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'prettier', 'import'],
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:vue/vue3-recommended', 'prettier'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx', '*.vue', '*d.ts'],
|
||||
rules: {
|
||||
'prefer-const': 0,
|
||||
'no-undef': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
rules: {
|
||||
// js/ts
|
||||
// 'no-console': ['warn', { allow: ['error'] }],
|
||||
'no-restricted-syntax': ['error', 'LabeledStatement', 'WithStatement'],
|
||||
camelcase: ['error', { properties: 'never' }],
|
||||
|
||||
'no-var': 'error',
|
||||
'no-empty': ['error', { allowEmptyCatch: true }],
|
||||
'no-void': 'error',
|
||||
'prefer-const': ['warn', { destructuring: 'all', ignoreReadBeforeAssign: true }],
|
||||
'prefer-template': 'error',
|
||||
'object-shorthand': ['error', 'always', { ignoreConstructors: false, avoidQuotes: true }],
|
||||
'block-scoped-var': 'error',
|
||||
'no-constant-condition': ['error', { checkLoops: false }],
|
||||
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
|
||||
// '@typescript-eslint/consistent-type-imports': ['error', { disallowTypeAnnotations: false }],
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
'no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
|
||||
// vue
|
||||
'vue/no-v-html': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/require-explicit-emits': 'off',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
|
||||
// prettier
|
||||
'prettier/prettier': 'error',
|
||||
|
||||
// import
|
||||
'import/first': 'error',
|
||||
'import/no-duplicates': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
|
||||
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: 'vue',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
{
|
||||
pattern: '@vue/**',
|
||||
group: 'external',
|
||||
position: 'before',
|
||||
},
|
||||
{
|
||||
pattern: 'ant-design-vue',
|
||||
group: 'internal',
|
||||
},
|
||||
],
|
||||
pathGroupsExcludedImportTypes: ['type'],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
* text=auto eol=lf
|
||||
*.ts linguist-detectable=false
|
||||
*.css linguist-detectable=false
|
||||
*.scss linguist-detectable=false
|
||||
*.js linguist-detectable=true
|
||||
*.vue linguist-detectable=true
|
||||
57
.github/workflows/gh-pages.yml
vendored
Normal file
57
.github/workflows/gh-pages.yml
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
name: syncToGitee
|
||||
env:
|
||||
# 7 GiB by default on GitHub, setting to 6 GiB
|
||||
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
jobs:
|
||||
repo-sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Node.js v14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14.x'
|
||||
|
||||
- name: Install
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: yarn build
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
with:
|
||||
publish_dir: ./dist
|
||||
personal_token: ${{ secrets.PERSONAL_TOKEN }}
|
||||
commit_message: Update ghPages
|
||||
force_orphan: true
|
||||
|
||||
- name: Mirror the Github organization repos to Gitee.
|
||||
uses: Yikun/hub-mirror-action@master
|
||||
with:
|
||||
src: 'github/buqiyuan'
|
||||
dst: 'gitee/buqiyuan'
|
||||
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
|
||||
dst_token: ${{ secrets.GITEE_TOKEN }}
|
||||
static_list: 'vite-vue3-h5'
|
||||
force_update: true
|
||||
debug: true
|
||||
|
||||
- name: Build Gitee Pages
|
||||
uses: yanglbme/gitee-pages-action@main
|
||||
with:
|
||||
# 注意替换为你的 Gitee 用户名
|
||||
gitee-username: buqiyuan
|
||||
# 注意在 Settings->Secrets 配置 GITEE_PASSWORD
|
||||
gitee-password: ${{ secrets.GITEE_PASSWORD }}
|
||||
# 注意替换为你的 Gitee 仓库,仓库名严格区分大小写,请准确填写,否则会出错
|
||||
gitee-repo: buqiyuan/vite-vue3-h5
|
||||
# 是否强制使用 HTTPS
|
||||
https: false
|
||||
# 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在)
|
||||
branch: gh-pages
|
||||
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
node_modules
|
||||
components.d.ts
|
||||
.DS_Store
|
||||
dist
|
||||
.npmrc
|
||||
.cache
|
||||
|
||||
public/version.json
|
||||
|
||||
tests/server/static
|
||||
tests/server/static/upload
|
||||
|
||||
.local
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
.eslintcache
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
*pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
# .vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
11
.prettierignore
Normal file
11
.prettierignore
Normal file
@ -0,0 +1,11 @@
|
||||
/dist/*
|
||||
.local
|
||||
.output.js
|
||||
/node_modules/**
|
||||
|
||||
.yarnrc
|
||||
|
||||
**/*.svg
|
||||
**/*.sh
|
||||
|
||||
/public/*
|
||||
2
.stylelintignore
Normal file
2
.stylelintignore
Normal file
@ -0,0 +1,2 @@
|
||||
/dist/*
|
||||
/public/*
|
||||
13
.vscode/extensions.json
vendored
Normal file
13
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"vue.volar",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"stylelint.vscode-stylelint",
|
||||
"esbenp.prettier-vscode",
|
||||
"mrmlnc.vscode-less",
|
||||
"lokalise.i18n-ally",
|
||||
"antfu.iconify",
|
||||
"mikestead.dotenv",
|
||||
"heybourn.headwind"
|
||||
]
|
||||
}
|
||||
13
.vscode/launch.json
vendored
Normal file
13
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome",
|
||||
"url": "http://localhost:3100",
|
||||
"webRoot": "${workspaceFolder}/src",
|
||||
"sourceMaps": true
|
||||
}
|
||||
]
|
||||
}
|
||||
104
.vscode/settings.json
vendored
Normal file
104
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
{
|
||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
"volar.tsPlugin": true,
|
||||
"volar.tsPluginStatus": false,
|
||||
"npm.packageManager": "yarn",
|
||||
"editor.tabSize": 2,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"files.eol": "\n",
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/*.log": true,
|
||||
"**/*.log*": true,
|
||||
"**/bower_components": true,
|
||||
"**/dist": true,
|
||||
"**/elehukouben": true,
|
||||
"**/.git": true,
|
||||
"**/.gitignore": true,
|
||||
"**/.svn": true,
|
||||
"**/.DS_Store": true,
|
||||
"**/.idea": true,
|
||||
"**/.vscode": false,
|
||||
"**/yarn.lock": true,
|
||||
"**/tmp": true,
|
||||
"out": true,
|
||||
"dist": true,
|
||||
"node_modules": true,
|
||||
"CHANGELOG.md": true,
|
||||
"examples": true,
|
||||
"res": true,
|
||||
"screenshots": true,
|
||||
"yarn-error.log": true,
|
||||
"**/.yarn": true
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/.cache": true,
|
||||
"**/.editorconfig": true,
|
||||
"**/.eslintcache": true,
|
||||
"**/bower_components": true,
|
||||
"**/.idea": true,
|
||||
"**/tmp": true,
|
||||
"**/.git": true,
|
||||
"**/.svn": true,
|
||||
"**/.hg": true,
|
||||
"**/CVS": true,
|
||||
"**/.DS_Store": true
|
||||
},
|
||||
"files.watcherExclude": {
|
||||
"**/.git/objects/**": true,
|
||||
"**/.git/subtree-cache/**": true,
|
||||
"**/.vscode/**": true,
|
||||
"**/node_modules/**": true,
|
||||
"**/tmp/**": true,
|
||||
"**/bower_components/**": true,
|
||||
"**/dist/**": true,
|
||||
"**/yarn.lock": true
|
||||
},
|
||||
"stylelint.enable": true,
|
||||
"stylelint.packageManager": "yarn",
|
||||
"path-intellisense.mappings": {
|
||||
"@/": "${workspaceRoot}/src"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[html]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[less]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[scss]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"[vue]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.stylelint": "explicit"
|
||||
}
|
||||
},
|
||||
"i18n-ally.localesPaths": ["src/locales/lang"],
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.sortKeys": true,
|
||||
"i18n-ally.namespace": true,
|
||||
"i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
|
||||
"i18n-ally.enabledParsers": ["ts"],
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.displayLanguage": "zh-CN",
|
||||
"i18n-ally.enabledFrameworks": ["vue", "react"]
|
||||
}
|
||||
8
.yarnrc
Normal file
8
.yarnrc
Normal file
@ -0,0 +1,8 @@
|
||||
registry "https://registry.npmmirror.com"
|
||||
|
||||
sass_binary_site "https://npmmirror.com/mirrors/node-sass/"
|
||||
phantomjs_cdnurl "http://cnpmjs.org/downloads"
|
||||
electron_mirror "https://npmmirror.com/mirrors/electron/"
|
||||
sqlite3_binary_host_mirror "https://foxgis.oss-cn-shanghai.aliyuncs.com/"
|
||||
profiler_binary_host_mirror "https://npmmirror.com/mirrors/node-inspector/"
|
||||
chromedriver_cdnurl "https://cdn.npm.taobao.org/dist/chromedriver"
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 bqy
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
39
README.md
Normal file
39
README.md
Normal file
@ -0,0 +1,39 @@
|
||||
## 移动端布局方案
|
||||
|
||||
移动端 vant3.x + vue3.x + vite2.x + ts.4.x + REM 布局 + Viewport (VW) 布局的实例运用
|
||||
|
||||
## 在线预览
|
||||
|
||||
http://buqiyuan.gitee.io/vite-vue3-h5
|
||||
|
||||
提供三个布局方案
|
||||
|
||||
**1. REM 布局**
|
||||
|
||||
使用 js 动态设置 html 的 font-size,css 使用 rem 单位,文本大小可选择使用 px
|
||||
|
||||
js 设置 viewport 的 scale 以支持高清设备的 1px
|
||||
|
||||
可设置页面最大最小宽度
|
||||
|
||||
**2. VW 布局**
|
||||
|
||||
css 使用 vw 单位,文本大小可选择使用 px
|
||||
|
||||
使用 transform 以支持高清设备的边框 1px(包括圆角),使用 @mixin `./vw/scss/_border.scss`
|
||||
|
||||
可设置容器固定纵横比,不可设置页面最大最小宽度
|
||||
|
||||
**3. REM + VW 布局**
|
||||
|
||||
html 的 font-size 使用 vw 单位,css 使用 rem 单位,文本大小可选择使用 px
|
||||
|
||||
使用 transform 以支持高清设备的边框 1px(包括圆角),使用 @mixin `./vw-rem/scss/_border.scss`
|
||||
|
||||
可设置容器固定纵横比,可设置页面最大最小宽度
|
||||
|
||||
## 使用
|
||||
|
||||
1. yarn dev
|
||||
|
||||
2. 业务代码中样式的调用方式可参考 `./rem/scss/rem.scss` 及 `./vw/scss/vw.scss` 及 `./vw-rem/scss/vw-rem.scss` 三个文件;可在 html 文件相应位置配置 `data-content-max` 属性来限制容器最大最小宽
|
||||
8
auto-imports.d.ts
vendored
Normal file
8
auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
// We suggest you to commit this file into source control
|
||||
declare global {
|
||||
interface Window {
|
||||
WeixinJSBridge: any;
|
||||
}
|
||||
}
|
||||
export {};
|
||||
13
commitlint.config.js
Normal file
13
commitlint.config.js
Normal file
@ -0,0 +1,13 @@
|
||||
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']],
|
||||
},
|
||||
};
|
||||
25
index.html
Normal file
25
index.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html data-content-max>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<link rel="stylesheet" href="./src/styles/common.scss" />
|
||||
<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 http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title>友福健康</title>
|
||||
</head>
|
||||
<style>
|
||||
body {
|
||||
overflow: hidden;
|
||||
transform: initial;
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
||||
<body data-content-max>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
20
mock/_createProductionServer.ts
Normal file
20
mock/_createProductionServer.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer';
|
||||
|
||||
const modules = import.meta.globEager('./**/*.ts');
|
||||
|
||||
const mockModules: any[] = [];
|
||||
Object.keys(modules).forEach((key) => {
|
||||
if (key.includes('/_')) {
|
||||
return;
|
||||
}
|
||||
mockModules.push(...modules[key].default);
|
||||
});
|
||||
|
||||
/**
|
||||
* Used in a production environment. Need to manually import all modules
|
||||
*/
|
||||
export function setupProdMockServer() {
|
||||
console.log('mockModules', mockModules);
|
||||
|
||||
createProdMockServer(mockModules);
|
||||
}
|
||||
56
mock/_util.ts
Normal file
56
mock/_util.ts
Normal file
@ -0,0 +1,56 @@
|
||||
// Interface data format used to return a unified format
|
||||
|
||||
export function resultSuccess<T = Recordable>(data: T, { message = 'ok' } = {}) {
|
||||
return {
|
||||
code: 200,
|
||||
data,
|
||||
message,
|
||||
type: 'success',
|
||||
};
|
||||
}
|
||||
|
||||
export function resultPageSuccess<T = any>(page: number, pageSize: number, list: T[], { message = 'ok' } = {}) {
|
||||
const pageData = pagination(page, pageSize, list);
|
||||
|
||||
return {
|
||||
...resultSuccess({
|
||||
list: pageData,
|
||||
pagination: {
|
||||
page: ~~page,
|
||||
size: ~~pageSize,
|
||||
total: list.length,
|
||||
},
|
||||
}),
|
||||
message,
|
||||
};
|
||||
}
|
||||
|
||||
export function resultError(message = 'Request failed', { code = -1, result = null } = {}) {
|
||||
return {
|
||||
code,
|
||||
result,
|
||||
message,
|
||||
type: 'error',
|
||||
};
|
||||
}
|
||||
|
||||
export function pagination<T = any>(page: number, pageSize: number, array: T[]): T[] {
|
||||
const offset = (page - 1) * Number(pageSize);
|
||||
const ret = offset + Number(pageSize) >= array.length ? array.slice(offset, array.length) : array.slice(offset, offset + Number(pageSize));
|
||||
return ret;
|
||||
}
|
||||
|
||||
export interface requestParams {
|
||||
method: string;
|
||||
body: any;
|
||||
headers?: { authorization?: string };
|
||||
query: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 本函数用于从request数据中获取token,请根据项目的实际情况修改
|
||||
*
|
||||
*/
|
||||
export function getRequestToken({ headers }: requestParams): string | undefined {
|
||||
return headers?.authorization;
|
||||
}
|
||||
12453
mock/log/_cateList.json
Normal file
12453
mock/log/_cateList.json
Normal file
File diff suppressed because it is too large
Load Diff
17
mock/log/index.ts
Normal file
17
mock/log/index.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { MockMethod } from 'vite-plugin-mock';
|
||||
import { resultSuccess } from '../_util';
|
||||
|
||||
import data from './_cateList.json';
|
||||
|
||||
export default [
|
||||
{
|
||||
url: '/mock-api/category/list',
|
||||
timeout: 0,
|
||||
method: 'get',
|
||||
response: ({ query }) => {
|
||||
console.log('query', query);
|
||||
|
||||
return resultSuccess(data);
|
||||
},
|
||||
},
|
||||
] as MockMethod[];
|
||||
10467
package-lock.json
generated
Normal file
10467
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
123
package.json
Normal file
123
package.json
Normal file
@ -0,0 +1,123 @@
|
||||
{
|
||||
"name": "vite-vue3-h5",
|
||||
"version": "0.0.0",
|
||||
"homepage": "git@buqiyuan.github.io/vite-vue3-h5",
|
||||
"scripts": {
|
||||
"serve": "npm run dev",
|
||||
"dev": "vite --host=0.0.0.0",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"deploy": "gh-pages -d dist",
|
||||
"format": "prettier --write ./src",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"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",
|
||||
"postversion": "git push && git push origin --tags",
|
||||
"reinstall": "rimraf yarn.lock && rimraf package.lock.json && rimraf node_modules && npm run dev",
|
||||
"version": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md",
|
||||
"test:gzip": "npx http-server dist --cors --gzip -c-1",
|
||||
"test:br": "npx http-server dist --cors --brotli -c-1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vant/area-data": "^1.5.1",
|
||||
"@vant/touch-emulator": "^1.3.2",
|
||||
"@vueuse/core": "^8.7.5",
|
||||
"axios": "^0.27.2",
|
||||
"bankcardinfo": "^2.0.6",
|
||||
"dayjs": "^1.11.3",
|
||||
"html2canvas": "^1.4.1",
|
||||
"js-md5": "^0.7.3",
|
||||
"jsbarcode": "^3.11.6",
|
||||
"lodash-es": "^4.17.21",
|
||||
"pinia": "^2.0.13",
|
||||
"qrcode": "^1.5.3",
|
||||
"qs": "^6.11.0",
|
||||
"vant": "^4.6.0",
|
||||
"vconsole": "^3.14.6",
|
||||
"vue": "^3.2.37",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-router": "^4.0.16",
|
||||
"weixin-js-sdk": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.3",
|
||||
"@commitlint/config-conventional": "^17.0.3",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/node": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"@typescript-eslint/parser": "^5.30.0",
|
||||
"@vitejs/plugin-legacy": "^1.8.2",
|
||||
"@vitejs/plugin-vue": "^2.3.3",
|
||||
"@vitejs/plugin-vue-jsx": "^1.3.10",
|
||||
"@vue/compiler-sfc": "3.2.33",
|
||||
"@vue/eslint-config-typescript": "^11.0.0",
|
||||
"commitizen": "^4.2.4",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^8.18.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-prettier": "^4.1.0",
|
||||
"eslint-plugin-vue": "^9.1.1",
|
||||
"gh-pages": "^4.0.0",
|
||||
"lint-staged": "^13.0.3",
|
||||
"mockjs": "^1.1.0",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-html": "^1.4.1",
|
||||
"postcss-scss": "^4.0.4",
|
||||
"prettier": "^2.7.1",
|
||||
"sass": "^1.53.0",
|
||||
"stylelint": "^14.9.1",
|
||||
"stylelint-config-html": "^1.0.0",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-recommended": "^8.0.0",
|
||||
"stylelint-config-recommended-vue": "^1.4.0",
|
||||
"stylelint-config-standard": "^26.0.0",
|
||||
"stylelint-order": "^5.0.0",
|
||||
"stylelint-scss": "^4.2.0",
|
||||
"swiper": "^8.0.3",
|
||||
"typescript": "^4.7.4",
|
||||
"unplugin-vue-components": "^0.20.1",
|
||||
"unplugin-vue-define-options": "^0.6.1",
|
||||
"vite": "^2.9.13",
|
||||
"vite-plugin-checker": "^0.4.6",
|
||||
"vite-plugin-mock": "^2.9.6",
|
||||
"vite-plugin-style-import": "^1.4.1",
|
||||
"vue-eslint-parser": "^9.0.3",
|
||||
"vue-tsc": "^0.38.2"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12 || >=14"
|
||||
},
|
||||
"lint-staged": {
|
||||
"./src/**/*.{js,jsx,ts,tsx,vue}": [
|
||||
"eslint --fix",
|
||||
"git add ."
|
||||
],
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
"eslint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
|
||||
"prettier --write"
|
||||
],
|
||||
"package.json": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.vue": [
|
||||
"eslint --fix",
|
||||
"prettier --write",
|
||||
"stylelint --fix"
|
||||
],
|
||||
"*.{scss,less,styl,html}": [
|
||||
"stylelint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
"*.md": [
|
||||
"prettier --write"
|
||||
]
|
||||
}
|
||||
}
|
||||
11
prettier.config.js
Normal file
11
prettier.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
printWidth: 800,
|
||||
semi: true,
|
||||
vueIndentScriptAndStyle: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
proseWrap: 'never',
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
endOfLine: 'auto',
|
||||
useTabs: false,
|
||||
};
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
151
src/App.vue
Normal file
151
src/App.vue
Normal file
@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<div class="ui-app">
|
||||
<router-view #="{ Component }">
|
||||
<keep-alive :include="include">
|
||||
<component :is="Component"></component>
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
<div v-if="showHome">
|
||||
<van-floating-bubble class="ui-bubble ui-home-bubble" axis="xy" magnetic="x" :gap="20">
|
||||
<template #default>
|
||||
<img class="ui-mgt-entrance" src="./assets/backHome.png" alt="" @click="jumpHome" />
|
||||
</template>
|
||||
</van-floating-bubble>
|
||||
</div>
|
||||
<div v-if="showContact">
|
||||
<van-floating-bubble class="ui-bubble ui-service-bubble" axis="xy" magnetic="x" :gap="20">
|
||||
<template #default>
|
||||
<img class="ui-mgt-entrance" src="./assets/contact.png" alt="" @click="contactService" />
|
||||
</template>
|
||||
</van-floating-bubble>
|
||||
</div>
|
||||
<van-tabbar v-show="isTabBarDemo" route active-color="#2a63b2" inactive-color="#333333">
|
||||
<template v-for="item in main" :key="item.name">
|
||||
<van-tabbar-item :to="item.path" replace>
|
||||
<span>{{ item.meta?.title }}</span>
|
||||
<template #icon="props">
|
||||
<img :src="props.active ? item.meta?.active : item.meta?.inactive" />
|
||||
</template>
|
||||
</van-tabbar-item>
|
||||
</template>
|
||||
</van-tabbar>
|
||||
<van-tabbar v-show="isTabBarDemoV2" route active-color="#2a63b2" inactive-color="#333333">
|
||||
<template v-for="item in mainV2" :key="item.name">
|
||||
<van-tabbar-item :to="item.path" replace>
|
||||
<span>{{ item.meta?.title }}</span>
|
||||
<template #icon="props">
|
||||
<img :src="props.active ? item.meta?.active : item.meta?.inactive" />
|
||||
</template>
|
||||
</van-tabbar-item>
|
||||
</template>
|
||||
</van-tabbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { main } from '@/router/modules/main';
|
||||
import { mainV2 } from '@/router/modules/mainV2';
|
||||
import { contactService } from '@/plugins/public';
|
||||
import router from '@/router';
|
||||
|
||||
// 需要缓存的页面
|
||||
const include = ref<any[]>(['AgentHome', 'TestControler', 'User', 'ShopOrderList', 'LeaseShopOrderList', 'LeaseShopDetail', 'appShopDetail']);
|
||||
// 不需要展示联系客服浮标的页面
|
||||
const notArrContact = ref<any[]>(['agentHome', 'testControler', 'user', 'appShopDetail', 'appShopOrderConfirm', 'appMyAddress', 'appAddAddress', 'longPicture', 'appShopAgreement', 'appUserLogin', 'dietaryHabitTest']);
|
||||
// 不需要展示返回主页浮标的页面
|
||||
const notArrHome = ref<any[]>(['shopRegister', 'agentHome', 'shopOrderConfirm', 'testControler', 'user', 'appShopDetail', 'appShopOrderConfirm', 'appMyAddress', 'appAddAddress', 'longPicture', 'appShopAgreement', 'appUserLogin', 'dietaryHabitTest']);
|
||||
|
||||
// 特定页面展示tabBar组件
|
||||
const isTabBarDemo = ref(false);
|
||||
const isTabBarDemoV2 = ref(false);
|
||||
|
||||
const showContact = ref(false);
|
||||
const showHome = ref(false);
|
||||
const route = ref<any>(null);
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.path,
|
||||
(newRoute) => {
|
||||
// 监听不需要展示联系客服浮标的页面
|
||||
if (notArrContact.value.includes(newRoute.split('/')[1])) {
|
||||
showContact.value = false;
|
||||
} else {
|
||||
showContact.value = true;
|
||||
}
|
||||
// 监听不需要展示返回主页浮标的页面
|
||||
if (notArrHome.value.includes(newRoute.split('/')[1])) {
|
||||
showHome.value = false;
|
||||
} else {
|
||||
showHome.value = true;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value,
|
||||
(e) => {
|
||||
if (e.name === 'agentHome' || e.name === 'testControler' || e.name === 'user') {
|
||||
isTabBarDemo.value = true;
|
||||
} else {
|
||||
isTabBarDemo.value = false;
|
||||
}
|
||||
console.log(e, '888888888');
|
||||
if (e.name === 'agentHomeV2' || e.name === 'userV2') {
|
||||
isTabBarDemoV2.value = true;
|
||||
} else {
|
||||
isTabBarDemoV2.value = false;
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
);
|
||||
|
||||
// 回到首页
|
||||
const jumpHome = () => {
|
||||
router.replace({
|
||||
name: 'agentHome',
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
route.value = router.currentRoute.value;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html {
|
||||
@include root-font-size();
|
||||
}
|
||||
|
||||
.ui-app {
|
||||
--container-height: 100vh;
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.van-pull-refresh {
|
||||
min-height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ui-bubble {
|
||||
overflow: initial;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ui-home-bubble {
|
||||
top: px2rem(-320);
|
||||
}
|
||||
|
||||
.ui-service-bubble {
|
||||
top: px2rem(-160);
|
||||
}
|
||||
</style>
|
||||
63
src/api/demo.ts
Normal file
63
src/api/demo.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import request from '@/utils/request';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
|
||||
// 登录
|
||||
export function getLogin() {
|
||||
return requestGo({
|
||||
hideLoading: true,
|
||||
url: '/h5/v1/auth/login',
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
// 微信、企业微信config配置
|
||||
export function getWxConfig() {
|
||||
let data = { url: window.location.href.split('#')[0] };
|
||||
return request({
|
||||
hideLoading: true,
|
||||
data,
|
||||
url: '/h5/work/js/sdk/config/v2',
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
// 授权失败后传递cookie和session给后端
|
||||
export function postCookie(e, i, j) {
|
||||
let data = `openid=${j}${JSON.stringify(e)}${i}`;
|
||||
return request({
|
||||
hideLoading: true,
|
||||
url: `/h5/report/error/data?data=${data}`,
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
// 阿里云上传配置
|
||||
export function getALiYun(token) {
|
||||
let data = token;
|
||||
return request({
|
||||
data,
|
||||
hideLoading: true,
|
||||
url: 'get/oss/config',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
// 获取版本号
|
||||
export function getVersion() {
|
||||
return request({
|
||||
hideLoading: true,
|
||||
url: 'get/version?type=0',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
// // 企业微信config配置
|
||||
// export function getAuthTicket() {
|
||||
// let data = { url: window.location.href.split('#')[0], type: 'app' };
|
||||
// return weChat({
|
||||
// hideLoading: true,
|
||||
// data,
|
||||
// url: '/h5/work/js/sdk/config',
|
||||
// method: 'post',
|
||||
// });
|
||||
// }
|
||||
14
src/api/models/userModel.ts
Normal file
14
src/api/models/userModel.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// 用户登录参数
|
||||
export interface LoginParams {
|
||||
account: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 登录成功返回结果
|
||||
*/
|
||||
export interface LoginResult {
|
||||
username: string;
|
||||
avatar: string;
|
||||
token: string;
|
||||
}
|
||||
15
src/api/user.ts
Normal file
15
src/api/user.ts
Normal file
@ -0,0 +1,15 @@
|
||||
// import { LoginParams, LoginResult } from './models/userModel';
|
||||
// import request from '@/utils/request';
|
||||
|
||||
// enum Api {
|
||||
// getUserId = '/base/appLogin', // 获取用户userid
|
||||
// }
|
||||
|
||||
// 根据code获取userid / token
|
||||
// export function getUserId(data: LoginParams) {
|
||||
// return request<LoginResult>({
|
||||
// url: Api.getUserId,
|
||||
// method: 'post',
|
||||
// data,
|
||||
// });
|
||||
// }
|
||||
BIN
src/assets/backHome.png
Normal file
BIN
src/assets/backHome.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/contact.png
Normal file
BIN
src/assets/contact.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
111
src/components/dynamicSkuSelector.vue
Normal file
111
src/components/dynamicSkuSelector.vue
Normal file
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="(spec, index) in currentSpecs" :key="index" class="ui-sku-list">
|
||||
<div class="font_28 color3 bold">{{ spec.name }}</div>
|
||||
<div class="f-fcl f-wrap">
|
||||
<template v-if="!props.showOnlySelected">
|
||||
<!-- 正常模式:显示所有选项 -->
|
||||
<div v-for="(item, itemIndex) in spec.spec" :key="itemIndex" class="font_26 f-fbc color3 ui-pt-16" :class="[props.disabled && !isSelected([...path, itemIndex]) ? 'ui-sku-item-disabled' : '']" @click="!props.disabled && selectSpec([...path, itemIndex])">
|
||||
<div class="ui-sku-item" :class="isSelected([...path, itemIndex]) ? 'ui-sku-item-active colorF' : 'color3'">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<!-- 只显示最终层级的选中项 -->
|
||||
<template v-if="isFinalLevel">
|
||||
<div v-for="(item, itemIndex) in spec.spec" :key="itemIndex" class="font_26 f-fbc color3 ui-pt-16">
|
||||
<div v-if="isSelected([...path, itemIndex])" class="ui-sku-item ui-sku-item-active colorF">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- 子规格处理 - 只在非最终层级且有选中项时继续递归 -->
|
||||
<template v-if="!isFinalLevel">
|
||||
<template v-for="(item, itemIndex) in spec.spec" :key="`sub-${itemIndex}`">
|
||||
<div v-if="hasSubSpec(item) && isSelected([...path, itemIndex])">
|
||||
<dynamic-sku-selector :specs="getSubSpecs(item)" :disabled="props.disabled" :show-only-selected="props.showOnlySelected" :path="[...path, itemIndex]" :selected-path="selectedPath" @select="!props.disabled && $emit('select', $event)" />
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
specs: Array,
|
||||
path: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
selectedPath: Array,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showOnlySelected: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['select']);
|
||||
|
||||
const currentSpecs = computed(() => props.specs);
|
||||
|
||||
// 计算是否为最终层级
|
||||
const isFinalLevel = computed(() => {
|
||||
if (!props.showOnlySelected) return false;
|
||||
|
||||
// 检查当前路径是否已经达到selectedPath的完整长度
|
||||
return props.path.length >= props.selectedPath.length - 1;
|
||||
});
|
||||
|
||||
const selectSpec = (fullPath) => {
|
||||
console.log(fullPath, 'fullPath===');
|
||||
emit('select', fullPath);
|
||||
};
|
||||
|
||||
const isSelected = (checkPath) => {
|
||||
return props.selectedPath.slice(0, checkPath.length).every((val, i) => val === checkPath[i]);
|
||||
};
|
||||
|
||||
const hasSubSpec = (item) => {
|
||||
return item.sub_spec && item.sub_spec.spec && Array.isArray(item.sub_spec.spec) && item.sub_spec.spec.length > 0;
|
||||
};
|
||||
|
||||
const getSubSpecs = (item) => {
|
||||
return hasSubSpec(item) ? [item.sub_spec] : [];
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ui-sku-list {
|
||||
.ui-sku-item,
|
||||
.ui-sku-item-active {
|
||||
padding: px2rem(12) px2rem(24);
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(20);
|
||||
margin-bottom: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-sku-item-active {
|
||||
background: #2a63b2;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ui-sku-item-disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
57
src/components/richTextParsing.vue
Normal file
57
src/components/richTextParsing.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div class="richTextParsing">
|
||||
<div class="rich_text" @click="imagePreview($event)" v-html="richText"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { showImagePreview } from 'vant';
|
||||
|
||||
defineProps({
|
||||
richText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
const imagePreview = (e) => {
|
||||
if (e.target.tagName === 'IMG') {
|
||||
showImagePreview({
|
||||
images: [e.target.currentSrc],
|
||||
showIndex: false,
|
||||
loop: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.richTextParsing {
|
||||
padding-bottom: px2rem(60);
|
||||
}
|
||||
|
||||
.rich_text {
|
||||
::v-deep(img) {
|
||||
max-width: 100% !important;
|
||||
max-height: 100% !important;
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.rich_text {
|
||||
font-size: px2rem(30);
|
||||
|
||||
::v-deep(img) {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.van-image-preview {
|
||||
z-index: 99999999999999 !important;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
</style>
|
||||
108
src/components/sharePoster.vue
Normal file
108
src/components/sharePoster.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="ui-sharePoster">
|
||||
<slot name="sharePoster"></slot>
|
||||
<!--海报生成后容器-->
|
||||
<div ref="wrapper" class="ui-wrapper"></div>
|
||||
<!--展示海报图片-->
|
||||
<van-popup v-model:show="show" :duration="0.5" :close-on-click-overlay="false">
|
||||
<div class="ui-posters-box">
|
||||
<img class="ui-posters-img" :src="posterImg" alt="" />
|
||||
<div class="font_28 colorF bold text-center ui-mt-20">长按保存图片,分享给好友或朋友圈</div>
|
||||
<img class="ui-cancel-icon" src="https://image.fulllinkai.com/202108/27/78698e898cd570e5e7751c323e4a5cb7.png" alt="" @click="remove" />
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, nextTick, ref } from 'vue';
|
||||
import html2canvas from 'html2canvas';
|
||||
import { closeToast, showLoadingToast } from 'vant';
|
||||
|
||||
const show = ref(false); // 展示隐藏海报
|
||||
const wrapper = ref<any>(null); // 海报生成后容器
|
||||
const lock = ref(1); // 防止多次生成海报
|
||||
|
||||
const posterImg = ref<any>(''); // 生成后的海报图片
|
||||
|
||||
const isShow = () => {
|
||||
showLoadingToast('');
|
||||
html2canvas(document.querySelector('#capture') as any, {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0)',
|
||||
scale: window.devicePixelRatio,
|
||||
})
|
||||
.then((canvas) => {
|
||||
canvas.style.width = `600px`;
|
||||
canvas.style.height = `1068px`;
|
||||
posterImg.value = canvas.toDataURL();
|
||||
wrapper.value.appendChild(canvas);
|
||||
lock.value = 0;
|
||||
show.value = true;
|
||||
closeToast();
|
||||
})
|
||||
.catch(() => {
|
||||
closeToast();
|
||||
});
|
||||
};
|
||||
|
||||
const remove = () => {
|
||||
show.value = false;
|
||||
if (!lock.value) {
|
||||
lock.value = 1;
|
||||
wrapper.value.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
//暴露方法和属性给父组件
|
||||
defineExpose({ isShow, remove });
|
||||
|
||||
nextTick(() => {});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-sharePoster {
|
||||
.van-popup {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
overflow-y: initial;
|
||||
}
|
||||
|
||||
.van-popup--center {
|
||||
top: 46%;
|
||||
}
|
||||
|
||||
.van-popup--round {
|
||||
border-radius: px2rem(16);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.ui-wrapper {
|
||||
position: fixed;
|
||||
top: px2rem(-100000);
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ui-posters-box {
|
||||
width: px2rem(600);
|
||||
height: px2rem(1068);
|
||||
border-radius: px2rem(12);
|
||||
position: relative;
|
||||
|
||||
.ui-posters-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-cancel-icon {
|
||||
width: px2rem(60);
|
||||
height: px2rem(60);
|
||||
top: px2rem(10);
|
||||
position: absolute;
|
||||
right: px2rem(-24);
|
||||
transform: translate(-50%);
|
||||
z-index: 9999;
|
||||
}
|
||||
</style>
|
||||
107
src/components/sharePosterV2.vue
Normal file
107
src/components/sharePosterV2.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div class="ui-sharePoster">
|
||||
<slot name="sharePoster"></slot>
|
||||
<!--海报生成后容器-->
|
||||
<div ref="wrapper" class="ui-wrapper"></div>
|
||||
<!--展示海报图片-->
|
||||
<van-popup v-model:show="show" :duration="0.5" :close-on-click-overlay="false">
|
||||
<div class="ui-posters-box">
|
||||
<img class="ui-posters-img" :src="posterImg" alt="" />
|
||||
</div>
|
||||
</van-popup>
|
||||
<div v-if="show" class="ui-cancel-box f-fcc font_32 color3" @click="remove">取消</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineExpose, nextTick, ref } from 'vue';
|
||||
import html2canvas from 'html2canvas';
|
||||
import { closeToast, showLoadingToast } from 'vant';
|
||||
|
||||
const show = ref(false); // 展示隐藏海报
|
||||
const wrapper = ref<any>(null); // 海报生成后容器
|
||||
const lock = ref(1); // 防止多次生成海报
|
||||
|
||||
const posterImg = ref<any>(''); // 生成后的海报图片
|
||||
|
||||
const isShow = () => {
|
||||
showLoadingToast('');
|
||||
html2canvas(document.querySelector('#capture') as any, {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0)',
|
||||
scale: window.devicePixelRatio,
|
||||
})
|
||||
.then((canvas) => {
|
||||
canvas.style.width = `600px`;
|
||||
canvas.style.height = `1068px`;
|
||||
posterImg.value = canvas.toDataURL();
|
||||
wrapper.value.appendChild(canvas);
|
||||
lock.value = 0;
|
||||
show.value = true;
|
||||
closeToast();
|
||||
})
|
||||
.catch(() => {
|
||||
closeToast();
|
||||
});
|
||||
};
|
||||
|
||||
const remove = () => {
|
||||
show.value = false;
|
||||
if (!lock.value) {
|
||||
lock.value = 1;
|
||||
wrapper.value.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
//暴露方法和属性给父组件
|
||||
defineExpose({ isShow, remove });
|
||||
|
||||
nextTick(() => {});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-sharePoster {
|
||||
.van-popup {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
overflow-y: initial;
|
||||
}
|
||||
|
||||
.van-popup--center {
|
||||
top: 46%;
|
||||
}
|
||||
|
||||
.van-popup--round {
|
||||
border-radius: px2rem(16);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.ui-wrapper {
|
||||
position: fixed;
|
||||
top: px2rem(-100000);
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ui-posters-box {
|
||||
width: px2rem(482);
|
||||
height: px2rem(806);
|
||||
border-radius: px2rem(16);
|
||||
position: relative;
|
||||
|
||||
.ui-posters-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-cancel-box {
|
||||
width: 100vw;
|
||||
padding: px2rem(36) 0 px2rem(90) 0;
|
||||
background: #ffffff;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 10000000;
|
||||
}
|
||||
</style>
|
||||
86
src/components/uploadPicture.vue
Normal file
86
src/components/uploadPicture.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<van-uploader :after-read="afterRead" :multiple="multiple" :max-count="maxCount" accept="image/*">
|
||||
<slot></slot>
|
||||
</van-uploader>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { showToast } from 'vant';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
|
||||
defineProps({
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxCount: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const state = ref(false);
|
||||
|
||||
const emit = defineEmits(['onSuccess']);
|
||||
|
||||
const afterRead = (file) => {
|
||||
state.value = false;
|
||||
console.log(file, '7777');
|
||||
if (file && file.length > 1) {
|
||||
file.forEach((item) => {
|
||||
if (item.status === 'failed') {
|
||||
showToast('网络异常,请重试');
|
||||
state.value = true;
|
||||
}
|
||||
if (item.file.size >= 10400 * 1024) {
|
||||
state.value = true;
|
||||
showToast('文件大小不能超过 10M');
|
||||
return;
|
||||
}
|
||||
});
|
||||
if (!state.value) {
|
||||
file.forEach((item) => {
|
||||
submit(item.file);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (file.status === 'failed') {
|
||||
showToast('网络异常,请重试');
|
||||
}
|
||||
if (file.file.size >= 10400 * 1024) {
|
||||
showToast('文件大小不能超过 10M');
|
||||
return;
|
||||
}
|
||||
submit(file.file);
|
||||
}
|
||||
};
|
||||
|
||||
const submit = (e) => {
|
||||
let data = {
|
||||
file: e,
|
||||
};
|
||||
requestGo({
|
||||
url: `h5/v1/common/oss/uploadfile`,
|
||||
data,
|
||||
method: 'post',
|
||||
headers: {
|
||||
'content-type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
let result = res.data;
|
||||
emit('onSuccess', result);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-image .van-empty__image {
|
||||
width: px2rem(180);
|
||||
height: px2rem(180);
|
||||
}
|
||||
</style>
|
||||
10
src/definition.d.ts
vendored
Normal file
10
src/definition.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
getIosToken: any; // 苹果全局变量名
|
||||
getAndroidPhone: any; // 安卓全局变量名
|
||||
webAppInterface: any; // 安卓全局变量名
|
||||
webkit: any; // ios app全局变量名
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
49
src/layout/index.vue
Normal file
49
src/layout/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<van-sticky ref="stickyRef">
|
||||
<van-nav-bar :title="$route.meta?.title">
|
||||
<template #left>
|
||||
<van-icon name="wap-nav" size="18" />
|
||||
</template>
|
||||
<template #right>
|
||||
<van-icon name="search" size="18" />
|
||||
</template>
|
||||
</van-nav-bar>
|
||||
</van-sticky>
|
||||
<div class="container">
|
||||
<router-view #="{ Component }">
|
||||
<keep-alive>
|
||||
<component :is="Component"></component>
|
||||
</keep-alive>
|
||||
</router-view>
|
||||
</div>
|
||||
<van-tabbar ref="tabbarRef" route>
|
||||
<template v-for="item in main" :key="item.name">
|
||||
<van-tabbar-item :to="item.path" :icon="item.meta?.icon"> {{ item.meta?.title }} </van-tabbar-item>
|
||||
</template>
|
||||
</van-tabbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick } from 'vue';
|
||||
import { Sticky, Tabbar } from 'vant';
|
||||
import { main } from '@/router/modules/main';
|
||||
|
||||
defineOptions({ name: 'Layout' });
|
||||
|
||||
const stickyRef = ref<InstanceType<typeof Sticky>>();
|
||||
const tabbarRef = ref<InstanceType<typeof Tabbar>>();
|
||||
const containerHeight = ref('');
|
||||
|
||||
nextTick(() => {
|
||||
containerHeight.value = `${stickyRef.value?.$el?.offsetHeight + tabbarRef.value?.$el.offsetHeight}px`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
--height: v-bind('containerHeight');
|
||||
--container-height: calc(100vh - var(--height));
|
||||
height: calc(100vh - var(--height));
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
16
src/main.ts
Normal file
16
src/main.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import { setupPlugins } from './plugins';
|
||||
import { setupStore } from './store';
|
||||
import { setupRouter } from './router';
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
// 安装插件(vant-ui等),若使用了 vite-plugin-components 插件,则需要手动引入组件
|
||||
setupPlugins(app);
|
||||
// 安装vuex
|
||||
setupStore(app);
|
||||
// 安装router
|
||||
setupRouter(app);
|
||||
|
||||
app.mount('#app');
|
||||
39
src/plugins/compress.ts
Normal file
39
src/plugins/compress.ts
Normal file
@ -0,0 +1,39 @@
|
||||
// 图片压缩
|
||||
const fileToDataURL = (file: Blob): Promise<any> => {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = (e) => resolve((e.target as FileReader).result);
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
};
|
||||
|
||||
const dataURLToImage = (dataURL: string): Promise<HTMLImageElement> => {
|
||||
return new Promise((resolve) => {
|
||||
const img = new Image();
|
||||
img.onload = () => resolve(img);
|
||||
img.src = dataURL;
|
||||
});
|
||||
};
|
||||
|
||||
const canvastoFile = (canvas: HTMLCanvasElement, type: string, quality: number): Promise<Blob | null> => {
|
||||
return new Promise((resolve) => canvas.toBlob((blob) => resolve(blob), type, quality));
|
||||
};
|
||||
|
||||
export const compressionFile = async (file, type = 'image/jpeg', quality = 0.5) => {
|
||||
const fileName = file.name;
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
const base64 = await fileToDataURL(file);
|
||||
const img = await dataURLToImage(base64);
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
context.clearRect(0, 0, img.width, img.height);
|
||||
context.drawImage(img, 0, 0, img.width, img.height);
|
||||
const blob = (await canvastoFile(canvas, type, quality)) as Blob; // quality:0.5可根据实际状况核算
|
||||
const newFile = await new File([blob], fileName, {
|
||||
type,
|
||||
});
|
||||
return newFile;
|
||||
};
|
||||
|
||||
export default compressionFile;
|
||||
8
src/plugins/index.ts
Normal file
8
src/plugins/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { App } from 'vue';
|
||||
import './vant';
|
||||
// import { vantPlugins } from './vant';
|
||||
|
||||
export const setupPlugins = (app: App) => {
|
||||
// app.use(vantPlugins);
|
||||
console.log('app', app);
|
||||
};
|
||||
248
src/plugins/public.ts
Normal file
248
src/plugins/public.ts
Normal file
@ -0,0 +1,248 @@
|
||||
import { showToast } from 'vant';
|
||||
import wx from 'weixin-js-sdk';
|
||||
import router from '@/router';
|
||||
|
||||
// 回填登录数据
|
||||
export const backFillLoginData = (result, userStore) => {
|
||||
userStore.userID = result.id;
|
||||
userStore.agentName = result.name || '----';
|
||||
userStore.agentAvatar = result.avatar || 'https://image.fulllinkai.com/202203/09/cc1c73eb1a4941fef25a15cd1ff2f9df.png';
|
||||
userStore.agentMobile = result.mobile || '';
|
||||
userStore.token = result.token;
|
||||
localStorage.setItem('rt_token', result.token);
|
||||
localStorage.setItem('rt_openid', result.openid as any);
|
||||
// userStore.isAgent = result.is_agent;
|
||||
// userStore.registerAgent = result.mobile ? 1 : 0;
|
||||
|
||||
localStorage.setItem('userStore', JSON.stringify(result));
|
||||
};
|
||||
|
||||
export const examineRegister = (to) => {
|
||||
// 批发商自定义分享页面进入后不是批发商先去注册,注册后回到分享的指定页面
|
||||
localStorage.setItem('jumpRtPathName', to.name as any);
|
||||
localStorage.setItem('jumpRtPathQuery', JSON.stringify(to.query));
|
||||
localStorage.setItem('jumpRtPathParams', JSON.stringify(to.params));
|
||||
router.replace({
|
||||
name: 'shopRegister',
|
||||
});
|
||||
};
|
||||
|
||||
// 图片转base64
|
||||
export const imageConversion = (url) => {
|
||||
return new Promise((resolve) => {
|
||||
let img = new Image();
|
||||
img.setAttribute('crossOrigin', 'anonymous'); // 解决iOS微信端报错 securityError...insource啥的、
|
||||
img.crossOrigin = 'Anonymous';
|
||||
img.onload = () => {
|
||||
// 一定要在onload后去压缩转码,否则可能因图片未加载传入,报错或者undefind之类的
|
||||
let base64 = getBase64Image(img);
|
||||
resolve(base64);
|
||||
};
|
||||
img.src = `${url}?v=${Math.random()}`; // 处理缓存
|
||||
});
|
||||
};
|
||||
|
||||
const getBase64Image = (img) => {
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
let ctx = canvas.getContext('2d') as any;
|
||||
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||
let dataURL = canvas.toDataURL('image/jpeg'); // 可选其他值 image/jpeg
|
||||
return dataURL;
|
||||
};
|
||||
|
||||
// 联系客服
|
||||
export const contactService = () => {
|
||||
window.location.href = `https://work.weixin.qq.com/kfid/kfcb38dad0cf7512ec9`;
|
||||
};
|
||||
|
||||
// 禁止微信分享
|
||||
export const hideShare = (wxConfig) => {
|
||||
wx.config(wxConfig.wxConfig);
|
||||
wx.checkJsApi({
|
||||
jsApiList: wxConfig.wxConfig.jsApiList, // 需要检测的JS接口列表
|
||||
success(res) {
|
||||
console.log(res);
|
||||
},
|
||||
});
|
||||
wx.ready(function () {
|
||||
wx.hideMenuItems({
|
||||
menuList: ['menuItem:copyUrl', 'menuItem:share:appMessage', 'menuItem:share:timeline', 'menuItem:share:qq', 'menuItem:share:weiboApp', 'menuItem:favorite', 'menuItem:share:facebook', 'menuItem:share:QZone'], // 屏蔽复制链接和相关分享
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 截取路由?号后参数,去重重新赋值,type:正常跳转为query || 授权跳转为url
|
||||
export const CutOutQuery = (e, type) => {
|
||||
let analyze = decodeURIComponent(e);
|
||||
// let analyzeT = analyze.split('?#')[1];
|
||||
let str = analyze.replace('?', '&').split(/[? &]/);
|
||||
let newStr = [...new Set(str)] as any;
|
||||
if (type == 'query') {
|
||||
let query = {};
|
||||
newStr.forEach((item) => {
|
||||
if (item.includes('=')) {
|
||||
let queryArray = item.split('=');
|
||||
query[queryArray[0]] = queryArray[1];
|
||||
}
|
||||
});
|
||||
console.log(query, '-------------------');
|
||||
return query;
|
||||
} else {
|
||||
let query = ``;
|
||||
newStr.forEach((item, index) => {
|
||||
if (item.includes('=') && index == 1) {
|
||||
query += `?${item}`;
|
||||
} else if (item.includes('=')) {
|
||||
query += `&${item}`;
|
||||
} else {
|
||||
query += `${item}`;
|
||||
}
|
||||
});
|
||||
console.log(query, '-------------------');
|
||||
return query;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前日期
|
||||
export const currentDate = () => {
|
||||
let year = new Date().getFullYear();
|
||||
let month = new Date().getMonth() + 1;
|
||||
let day = new Date().getDate();
|
||||
month = (month < 10 ? `0${month}` : month) as any;
|
||||
day = (day < 10 ? `0${day}` : day) as any;
|
||||
return `${year}-${month}-${day}`;
|
||||
};
|
||||
|
||||
// 日期转换
|
||||
export const formatData = (time) => {
|
||||
let timestamp = time.replace(/-/g, '/');
|
||||
timestamp = new Date(timestamp).getTime().toString(); // 补全为13位
|
||||
const minute = 1000 * 60;
|
||||
const hour = minute * 60;
|
||||
const day = hour * 24;
|
||||
const month = day * 30;
|
||||
const now = new Date().getTime();
|
||||
const diffValue = now - timestamp;
|
||||
// 计算差异的时间
|
||||
const monthC = diffValue / month;
|
||||
const weekC = diffValue / (7 * day);
|
||||
const dayC = diffValue / day;
|
||||
const hourC = diffValue / hour;
|
||||
const minC = diffValue / minute;
|
||||
// 数值补0方法
|
||||
const zero = function (value) {
|
||||
if (value < 10) {
|
||||
return `0${value}`;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
// 超过1年,直接显示年月日
|
||||
if (monthC > 12) {
|
||||
return (function () {
|
||||
const date = new Date(time);
|
||||
return `${date.getFullYear()}年${zero(date.getMonth() + 1)}月${zero(date.getDate())}日`;
|
||||
})();
|
||||
} else if (monthC >= 1) {
|
||||
return `${parseInt(monthC)}月前`;
|
||||
} else if (weekC >= 1) {
|
||||
return `${parseInt(weekC)}周前`;
|
||||
} else if (dayC >= 1) {
|
||||
return `${parseInt(dayC)}天前`;
|
||||
} else if (hourC >= 1) {
|
||||
return `${parseInt(hourC)}小时前`;
|
||||
} else if (minC >= 1) {
|
||||
return `${parseInt(minC)}分钟前`;
|
||||
}
|
||||
return '刚刚';
|
||||
};
|
||||
|
||||
// 倒计时
|
||||
export const countDown = (time) => {
|
||||
let startDateV2 = new Date(); // 开始时间
|
||||
let endTimeArrV2 = time.replace(/-/g, '/');
|
||||
let endDateV2 = new Date(endTimeArrV2); // 结束时间
|
||||
let t = endDateV2.getTime() - startDateV2.getTime(); // 时间差
|
||||
let d = 0;
|
||||
let h = 0;
|
||||
let m = 0;
|
||||
let s = 0;
|
||||
if (t >= 0) {
|
||||
d = Math.floor(t / 1000 / 3600 / 24);
|
||||
h = Math.floor((t / 1000 / 60 / 60) % 24);
|
||||
m = Math.floor((t / 1000 / 60) % 60);
|
||||
s = Math.floor((t / 1000) % 60);
|
||||
}
|
||||
// 数值补0方法
|
||||
const zero = function (value) {
|
||||
if (value < 10) {
|
||||
return `0${value}`;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
// 修改小时格式
|
||||
if (h >= 0 && h <= 9) {
|
||||
h = zero(h);
|
||||
}
|
||||
// 修改分钟格式
|
||||
if (m >= 0 && m <= 9) {
|
||||
m = zero(m);
|
||||
}
|
||||
// 修改秒格式
|
||||
if (s >= 0 && s <= 9) {
|
||||
s = zero(s);
|
||||
}
|
||||
return { d, h, m, s };
|
||||
};
|
||||
|
||||
// 复制内容
|
||||
export const copy = async (val, state) => {
|
||||
//创建input标签
|
||||
const input = document.createElement('input');
|
||||
//将input的值设置为需要复制的内容
|
||||
input.value = val;
|
||||
//添加input标签
|
||||
document.body.appendChild(input);
|
||||
//选中input标签
|
||||
input.select();
|
||||
//执行复制
|
||||
document.execCommand('copy');
|
||||
if (!state) {
|
||||
if (document.execCommand('copy')) {
|
||||
showToast('复制成功');
|
||||
} else {
|
||||
showToast('该浏览器暂不支持复制');
|
||||
}
|
||||
}
|
||||
//移除input标签
|
||||
document.body.removeChild(input);
|
||||
};
|
||||
|
||||
//封装防抖
|
||||
export const debounce = (fn, delay) => {
|
||||
let timer: null | ReturnType<typeof setTimeout> = null;
|
||||
return function () {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
timer = setTimeout(function () {
|
||||
fn.apply(1);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
//封装节流
|
||||
export const throttle = (fn, delay) => {
|
||||
let valid = true;
|
||||
return function () {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
valid = false;
|
||||
setTimeout(() => {
|
||||
fn.apply(2);
|
||||
valid = true;
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
11
src/plugins/vant.ts
Normal file
11
src/plugins/vant.ts
Normal file
@ -0,0 +1,11 @@
|
||||
// https://youzan.github.io/vant/v4/#/zh-CN/quickstart#4.-yin-ru-han-shu-zu-jian-de-yang-shi
|
||||
// Toast
|
||||
import 'vant/es/toast/style';
|
||||
// Dialog
|
||||
import 'vant/es/dialog/style';
|
||||
// Notify
|
||||
import 'vant/es/notify/style';
|
||||
// ImagePreview
|
||||
import 'vant/es/image-preview/style';
|
||||
|
||||
import '@vant/touch-emulator'; // 桌面端touch适配
|
||||
85
src/plugins/wxShare.ts
Normal file
85
src/plugins/wxShare.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import wx from 'weixin-js-sdk';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
export const weXinShare = (imgUrl: string, link: string, title: string, desc: string) => {
|
||||
let finalLink = link;
|
||||
|
||||
try {
|
||||
// 使用当前 origin 作为 base 解析 link
|
||||
const url = new URL(link, location.origin);
|
||||
|
||||
// 提取 hash(包含 # 和 ?query)
|
||||
const hash = url.hash; // 例如 "#/agentHome?from_user_id=123&from_type=rt_home"
|
||||
|
||||
// 构造新路径:/go_html/store_common (注意:结尾无 /)
|
||||
const newPath = '/go_html/store_common';
|
||||
|
||||
// 拼接最终链接
|
||||
finalLink = location.origin + newPath + hash;
|
||||
} catch (e) {
|
||||
// 如果 link 是纯 hash 路径,如 "#/agentHome?..."
|
||||
if (link.startsWith('#/')) {
|
||||
finalLink = `${location.origin}/go_html/store_common${link}`;
|
||||
} else if (link.startsWith('/store/')) {
|
||||
// 处理相对路径如 "/store/#/xxx"
|
||||
const hashPart = link.substring(link.indexOf('#'));
|
||||
finalLink = `${location.origin}/go_html/store_common${hashPart}`;
|
||||
} else if (link.startsWith('http') || link.startsWith('//')) {
|
||||
// 兜底:尝试手动提取 hash
|
||||
const hashIndex = link.indexOf('#');
|
||||
if (hashIndex !== -1) {
|
||||
const hash = link.substring(hashIndex);
|
||||
finalLink = `${location.origin}/go_html/store_common${hash}`;
|
||||
} else {
|
||||
// 没有 #,可能是错误输入,保留原样(或按需处理)
|
||||
finalLink = link;
|
||||
}
|
||||
} else {
|
||||
// 其他情况,保守处理
|
||||
finalLink = link;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('finalLink:', finalLink);
|
||||
|
||||
const userStore = useUserStore();
|
||||
wx.config(userStore.wxConfig);
|
||||
|
||||
wx.ready(() => {
|
||||
const shareData = {
|
||||
title,
|
||||
desc,
|
||||
link: finalLink,
|
||||
imgUrl,
|
||||
success() {
|
||||
console.log('分享成功');
|
||||
},
|
||||
cancel() {
|
||||
console.log('分享取消');
|
||||
},
|
||||
};
|
||||
|
||||
wx.updateAppMessageShareData(shareData);
|
||||
wx.updateTimelineShareData({
|
||||
title,
|
||||
link: finalLink,
|
||||
imgUrl,
|
||||
success() {
|
||||
console.log('朋友圈分享成功');
|
||||
},
|
||||
cancel() {
|
||||
console.log('朋友圈分享取消');
|
||||
},
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
wx.showMenuItems({
|
||||
menuList: ['menuItem:share:appMessage', 'menuItem:share:timeline'],
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
wx.error((err) => {
|
||||
console.error('微信分享 error:', err);
|
||||
});
|
||||
};
|
||||
250
src/router/index.ts
Normal file
250
src/router/index.ts
Normal file
@ -0,0 +1,250 @@
|
||||
import { App } from 'vue';
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||
import { createRouterGuards } from './routerGuards';
|
||||
import { main } from './modules/main';
|
||||
import { mainV2 } from './modules/mainV2';
|
||||
|
||||
export const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'agentHome',
|
||||
redirect: '/agentHome',
|
||||
children: [
|
||||
...main,
|
||||
...mainV2,
|
||||
{
|
||||
path: '/shopSearch',
|
||||
name: 'shopSearch',
|
||||
component: () => import('@/views/subDir/shopSearch.vue'),
|
||||
meta: {
|
||||
title: '搜索商品',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopDetail/:id',
|
||||
name: 'shopDetail',
|
||||
component: () => import('@/views/subDir/shopDetail.vue'),
|
||||
meta: {
|
||||
title: '商品详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopDetailV2/:id',
|
||||
name: 'shopDetailV2',
|
||||
component: () => import('@/views/subDir/shopDetailV2.vue'),
|
||||
meta: {
|
||||
title: '商品详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopDetailV3/:id',
|
||||
name: 'shopDetailV3',
|
||||
component: () => import('@/views/subDir/shopDetailV3.vue'),
|
||||
meta: {
|
||||
title: '商品详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopOrderConfirm',
|
||||
name: 'shopOrderConfirm',
|
||||
component: () => import('@/views/subDir/shopOrderConfirm.vue'),
|
||||
meta: {
|
||||
title: '确认订单',
|
||||
},
|
||||
},
|
||||
// //dma确认订单
|
||||
// {
|
||||
// path: '/shopOrderConfirmV2',
|
||||
// name: 'shopOrderConfirmV2',
|
||||
// component: () => import('@/views/subDir/shopOrderConfirmV2.vue'),
|
||||
// meta: {
|
||||
// title: '确认订单',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
path: '/appUserLogin',
|
||||
name: 'appUserLogin',
|
||||
component: () => import('@/views/subDir/appUserLogin.vue'),
|
||||
meta: {
|
||||
title: '登录',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopRegister',
|
||||
name: 'shopRegister',
|
||||
component: () => import('@/views/subDir/shopRegister.vue'),
|
||||
meta: {
|
||||
title: '个人资料',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopOrderDetail/:id',
|
||||
name: 'shopOrderDetail',
|
||||
component: () => import('@/views/subDir/shopOrderDetail.vue'),
|
||||
meta: {
|
||||
title: '订单详情',
|
||||
},
|
||||
},
|
||||
// 租赁商品详情
|
||||
{
|
||||
path: '/leaseShopDetail/:id',
|
||||
name: 'leaseShopDetail',
|
||||
component: () => import('@/views/subDir/leaseShopDetail.vue'),
|
||||
meta: {
|
||||
title: '商品详情',
|
||||
},
|
||||
},
|
||||
// 租赁商品确认订单
|
||||
{
|
||||
path: '/leaseShopOrderConfirm',
|
||||
name: 'leaseShopOrderConfirm',
|
||||
component: () => import('@/views/subDir/leaseShopOrderConfirm.vue'),
|
||||
meta: {
|
||||
title: '确认订单',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/leaseShopOrderList',
|
||||
name: 'leaseShopOrderList',
|
||||
component: () => import('@/views/subDir/leaseShopOrderList.vue'),
|
||||
meta: {
|
||||
title: '测试官订单',
|
||||
},
|
||||
},
|
||||
// 租赁商品订单详情
|
||||
{
|
||||
path: '/leaseShopOrderDetail/:id',
|
||||
name: 'leaseShopOrderDetail',
|
||||
component: () => import('@/views/subDir/leaseShopOrderDetail.vue'),
|
||||
meta: {
|
||||
title: '订单详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopOrderList',
|
||||
name: 'shopOrderList',
|
||||
component: () => import('@/views/subDir/shopOrderList.vue'),
|
||||
meta: {
|
||||
title: '我的订单',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/returnGoods/:id',
|
||||
name: 'returnGoods',
|
||||
component: () => import('@/views/subDir/returnGoods.vue'),
|
||||
meta: {
|
||||
title: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/returnGoodsDetail/:id',
|
||||
name: 'returnGoodsDetail',
|
||||
component: () => import('@/views/subDir/returnGoodsDetail.vue'),
|
||||
meta: {
|
||||
title: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopPrizeDrawCode',
|
||||
name: 'shopPrizeDrawCode',
|
||||
component: () => import('@/views/subDir/shopPrizeDrawCode.vue'),
|
||||
meta: {
|
||||
title: '我的抽奖码',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/shopAgreement/:id',
|
||||
name: 'shopAgreement',
|
||||
component: () => import('@/views/subDir/shopAgreement.vue'),
|
||||
meta: {
|
||||
title: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/testPage',
|
||||
name: 'testPage',
|
||||
component: () => import('@/views/userDir/testPage.vue'),
|
||||
meta: {
|
||||
title: '测试',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/appShopDetail/:id',
|
||||
name: 'appShopDetail',
|
||||
component: () => import('@/views/appDir/appShopDetail.vue'),
|
||||
meta: {
|
||||
title: '商品详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/appShopOrderConfirm',
|
||||
name: 'appShopOrderConfirm',
|
||||
component: () => import('@/views/appDir/appShopOrderConfirm.vue'),
|
||||
meta: {
|
||||
title: '确认订单',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/appMyAddress',
|
||||
name: 'appMyAddress',
|
||||
component: () => import('@/views/appDir/appMyAddress.vue'),
|
||||
meta: {
|
||||
title: '我的地址',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/appAddAddress',
|
||||
name: 'appAddAddress',
|
||||
component: () => import('@/views/appDir/appAddAddress.vue'),
|
||||
meta: {
|
||||
title: '添加地址',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'appShopAgreement/:id',
|
||||
name: 'appShopAgreement',
|
||||
component: () => import('@/views/appDir/appShopAgreement.vue'),
|
||||
meta: {
|
||||
title: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'longPicture',
|
||||
name: 'longPicture',
|
||||
component: () => import('@/views/appDir/longPicture.vue'),
|
||||
meta: {
|
||||
title: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/dietaryHabitTest',
|
||||
name: 'dietaryHabitTest',
|
||||
component: () => import('@/views/subDir/dietaryHabitTest.vue'),
|
||||
meta: {
|
||||
title: '心理测试',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/dietaryHabitList',
|
||||
name: 'dietaryHabitList',
|
||||
component: () => import('@/views/subDir/dietaryHabitList.vue'),
|
||||
meta: {
|
||||
title: '心理测试列表',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
// process.env.BASE_URL
|
||||
history: createWebHashHistory(''),
|
||||
routes,
|
||||
});
|
||||
|
||||
export function setupRouter(app: App) {
|
||||
app.use(router);
|
||||
// 创建路由守卫
|
||||
createRouterGuards(router);
|
||||
}
|
||||
export default router;
|
||||
37
src/router/modules/main.ts
Normal file
37
src/router/modules/main.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
export const main: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/agentHome',
|
||||
name: 'agentHome',
|
||||
component: () => import('@/views/tabBar/agentHome.vue'),
|
||||
meta: {
|
||||
title: '友福商城',
|
||||
icon: 'home-o',
|
||||
active: 'https://image.fulllinkai.com/202405/21/56d993df3bd2d5d21f10dfff63326ead.png',
|
||||
inactive: 'https://image.fulllinkai.com/202405/21/ae7d84d2b86dcba73107373e460f3762.png',
|
||||
},
|
||||
},
|
||||
// {
|
||||
// path: '/testControler',
|
||||
// name: 'testControler',
|
||||
// component: () => import('@/views/tabBar/testControler.vue'),
|
||||
// meta: {
|
||||
// title: '测试官',
|
||||
// icon: 'home-o',
|
||||
// active: 'https://image.fulllinkai.com/202406/07/40c9501378795c3ef38223e95cd98fbb.png',
|
||||
// inactive: 'https://image.fulllinkai.com/202406/07/d5bbd9cd97c8672415d343465a88860c.png',
|
||||
// },
|
||||
// },
|
||||
{
|
||||
path: '/user',
|
||||
name: 'user',
|
||||
component: () => import('@/views/tabBar/user.vue'),
|
||||
meta: {
|
||||
title: '我的',
|
||||
icon: 'cart-o',
|
||||
active: 'https://image.fulllinkai.com/202406/12/1a0d9053c7a3124f5e1feca9d8ff8f77.png',
|
||||
inactive: 'https://image.fulllinkai.com/202406/12/1ad2a21afa02dbfa65893693edaa4dae.png',
|
||||
},
|
||||
},
|
||||
];
|
||||
26
src/router/modules/mainV2.ts
Normal file
26
src/router/modules/mainV2.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
export const mainV2: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/agentHomeV2',
|
||||
name: 'agentHomeV2',
|
||||
component: () => import('@/views/tabBar/agentHomeV2.vue'),
|
||||
meta: {
|
||||
title: '友福商城',
|
||||
icon: 'home-o',
|
||||
active: 'https://image.fulllinkai.com/202405/21/56d993df3bd2d5d21f10dfff63326ead.png',
|
||||
inactive: 'https://image.fulllinkai.com/202405/21/ae7d84d2b86dcba73107373e460f3762.png',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/userV2',
|
||||
name: 'userV2',
|
||||
component: () => import('@/views/tabBar/userV2.vue'),
|
||||
meta: {
|
||||
title: '我的',
|
||||
icon: 'cart-o',
|
||||
active: 'https://image.fulllinkai.com/202406/12/1a0d9053c7a3124f5e1feca9d8ff8f77.png',
|
||||
inactive: 'https://image.fulllinkai.com/202406/12/1ad2a21afa02dbfa65893693edaa4dae.png',
|
||||
},
|
||||
},
|
||||
];
|
||||
124
src/router/routerGuards.ts
Normal file
124
src/router/routerGuards.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import { Router } from 'vue-router';
|
||||
import { getLogin } from '@/api/demo';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { backFillLoginData, hideShare } from '@/plugins/public';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
// import routerV2 from '@/router';
|
||||
|
||||
let pathUrls = ['shopReceipt', 'testPage', 'appAddAddress', 'appMyAddress', 'appShopDetail', 'appShopOrderConfirm', 'appShopAgreement', 'longPicture']; // 不需要登录的页面
|
||||
let initLogin = 1;
|
||||
|
||||
export function createRouterGuards(router: Router) {
|
||||
router.beforeEach((to, _from, next) => {
|
||||
document.title = (to?.meta?.title as string) || document.title;
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
setTimeout(() => {
|
||||
// 判断是否需要登录的页面
|
||||
let through = false;
|
||||
pathUrls.forEach((item) => {
|
||||
if (to.path.includes(item)) {
|
||||
through = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (to.query.openid) {
|
||||
localStorage.removeItem('rt_openid');
|
||||
localStorage.setItem('rt_openid', to.query.openid as any);
|
||||
history.back();
|
||||
}
|
||||
|
||||
window.onpageshow = function (e) {
|
||||
if (e.persisted) {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
// 分享人ID
|
||||
if (to.query.from_user_id) {
|
||||
localStorage.removeItem('rt_from_user_id');
|
||||
localStorage.setItem('rt_from_user_id', to.query.from_user_id as any);
|
||||
}
|
||||
|
||||
// 分享人ID
|
||||
if (to.query.form_open_id) {
|
||||
localStorage.removeItem('rt_form_open_id');
|
||||
localStorage.setItem('rt_form_open_id', to.query.form_open_id as any);
|
||||
}
|
||||
|
||||
// 邀请人ID
|
||||
if (to.query.invite_user_id) {
|
||||
localStorage.removeItem('rt_invite_user_id');
|
||||
localStorage.setItem('rt_invite_user_id', to.query.invite_user_id as any);
|
||||
}
|
||||
|
||||
// 推荐人ID
|
||||
if (to.query.referrer_user_id) {
|
||||
localStorage.removeItem('rt_referrer_user_id');
|
||||
localStorage.setItem('rt_referrer_user_id', to.query.referrer_user_id as any);
|
||||
}
|
||||
|
||||
// 来源
|
||||
if (to.query.from_type) {
|
||||
localStorage.removeItem('rt_from_type');
|
||||
localStorage.setItem('rt_from_type', to.query.from_type as any);
|
||||
}
|
||||
// 来源
|
||||
if (to.query.app_token) {
|
||||
localStorage.removeItem('app_token');
|
||||
localStorage.setItem('app_token', to.query.app_token as any);
|
||||
}
|
||||
|
||||
if (to.query.token) {
|
||||
localStorage.removeItem('rt_token');
|
||||
localStorage.setItem('rt_token', to.query.token as any);
|
||||
}
|
||||
|
||||
// 不是指定分享页面禁止分享
|
||||
if ((userStore.wxConfig as any).init != 'true' && localStorage.getItem('user_id')) {
|
||||
hideShare(useUserStore());
|
||||
}
|
||||
|
||||
// 无需登录的页面直接进入
|
||||
if (through) {
|
||||
next();
|
||||
} else {
|
||||
// 检测是否存在token,没有就登录
|
||||
if (initLogin <= 1) {
|
||||
getLogin().then((res) => {
|
||||
if (res.code === 0) {
|
||||
let result = res.data;
|
||||
// 微信分享配置接口
|
||||
const url = encodeURIComponent(location.href.split('#')[0]);
|
||||
requestGo({ url: `h5/v1/common/jssdk/config?url=${url}`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
userStore.wxConfig = res.data;
|
||||
localStorage.setItem('user_id', result.id);
|
||||
hideShare(useUserStore());
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
initLogin++;
|
||||
backFillLoginData(result, userStore);
|
||||
// if (!res.data.id) {
|
||||
// examineRegister(routerV2.currentRoute.value);
|
||||
// }
|
||||
next();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
|
||||
router.onError((error) => {
|
||||
const fetchResourcesErrors = ['Failed to fetch dynamically imported module', 'Importing a module script failed'];
|
||||
if (fetchResourcesErrors.some((item) => error?.message && error.message?.includes(item))) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
10
src/store/index.ts
Normal file
10
src/store/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { createPinia } from 'pinia';
|
||||
import type { App } from 'vue';
|
||||
|
||||
const store = createPinia();
|
||||
|
||||
export function setupStore(app: App<Element>) {
|
||||
app.use(store);
|
||||
}
|
||||
|
||||
export { store };
|
||||
80
src/store/modules/user.ts
Normal file
80
src/store/modules/user.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
interface UserState {
|
||||
init: number;
|
||||
token: string;
|
||||
partnerID: string;
|
||||
fromUserID: string;
|
||||
userID: string;
|
||||
wineMobile: string;
|
||||
wineName: string;
|
||||
name: string;
|
||||
agentName: string;
|
||||
avatar: string;
|
||||
agentAvatar: string;
|
||||
agentMobile: string;
|
||||
invitationCode: string;
|
||||
weChatBindState: string;
|
||||
chatId: string;
|
||||
userOfficeId: string;
|
||||
isAgent: string;
|
||||
registerAgent: string;
|
||||
userType: string;
|
||||
admin: string;
|
||||
dataState: string;
|
||||
partner: string;
|
||||
collaborator: string;
|
||||
service: string;
|
||||
emcee: string;
|
||||
coach: string;
|
||||
chef: string;
|
||||
chiefCoach: string;
|
||||
takeFood: number;
|
||||
uploadData: object;
|
||||
wallets: object;
|
||||
wxConfig: object;
|
||||
agentConfig: object;
|
||||
signature: object;
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore({
|
||||
id: 'user',
|
||||
state: (): UserState => ({
|
||||
init: 0,
|
||||
token: '',
|
||||
partnerID: '',
|
||||
fromUserID: '',
|
||||
userID: '',
|
||||
wineMobile: '', // 绑定酒所需回填手机号
|
||||
wineName: '', // 绑定酒所需回填用户名
|
||||
name: '',
|
||||
agentName: '', // 批发商姓名
|
||||
avatar: '',
|
||||
agentAvatar: '', // 批发商头像
|
||||
agentMobile: '', // 批发商手机
|
||||
invitationCode: '', // 邀请码
|
||||
weChatBindState: '',
|
||||
chatId: '',
|
||||
userOfficeId: '', // 用户绑定的所属办公室id
|
||||
isAgent: '', // 是否批发商 0:否,1:是
|
||||
registerAgent: '', // 是否注册了批发商 0:否,1:是(接口获取值不同)
|
||||
userType: '', // 用户角色类型 0: 客户,1: 兼职,2: 全职
|
||||
admin: '1', // 是否管理员
|
||||
dataState: '', // 资料状态
|
||||
partner: '', // 是否合伙人
|
||||
collaborator: '', // 是否合作商(加入友福)
|
||||
service: '', // 是否客服
|
||||
emcee: '', // 是否主持人
|
||||
coach: '', // 是否副教练
|
||||
chef: '', // 是否餐饮人员
|
||||
chiefCoach: '', // 是否主教练
|
||||
takeFood: 1,
|
||||
uploadData: {}, // 阿里云上传配置信息
|
||||
wallets: {}, // 钱包信息
|
||||
wxConfig: { init: 'true' }, // 储存微信凭证
|
||||
agentConfig: {}, // 储存企业微信凭证
|
||||
signature: {}, // 储存上传凭证
|
||||
}),
|
||||
getters: {},
|
||||
actions: {},
|
||||
});
|
||||
808
src/styles/common.scss
Normal file
808
src/styles/common.scss
Normal file
@ -0,0 +1,808 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@import './rem/scss/util';
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.break-all {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.f-fb {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.f-fbc {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.f-fl {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
.f-fcl {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.f-fc {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.f-fcc {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.f-fr {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
}
|
||||
|
||||
.f-fcr {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.f-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ellipsis_1 {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ellipsis_2 {
|
||||
display: -webkit-box; /* Safari */
|
||||
-webkit-line-clamp: 2; /* Safari and Chrome */
|
||||
-webkit-box-orient: vertical; /* Safari and Chrome */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ellipsis_3 {
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
}
|
||||
|
||||
.backCover {
|
||||
background-size: cover !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-position: center !important;
|
||||
}
|
||||
|
||||
.ui-relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-overflow {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.flo_l {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.flo_r {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.colorF {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.color3 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.color6 {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.color9 {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.colorF5 {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
.colorF8 {
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.colorC2 {
|
||||
color: #c2c2c2;
|
||||
}
|
||||
|
||||
.colorTheme {
|
||||
color: #5ac7a0;
|
||||
}
|
||||
|
||||
.colorBlue {
|
||||
color: #2a63b2;
|
||||
}
|
||||
|
||||
.colorAppGreen {
|
||||
color: #18CA6E;
|
||||
}
|
||||
|
||||
.colorPrice {
|
||||
color: #ff5959;
|
||||
}
|
||||
|
||||
.bcTheme {
|
||||
background: linear-gradient(90deg, #8c9bff 0%, #707ffa 100%);
|
||||
}
|
||||
|
||||
.font_14 {
|
||||
font-size: px2rem(14);
|
||||
}
|
||||
|
||||
.font_16 {
|
||||
font-size: px2rem(16);
|
||||
}
|
||||
|
||||
.font_18 {
|
||||
font-size: px2rem(18);
|
||||
}
|
||||
|
||||
.font_20 {
|
||||
font-size: px2rem(20);
|
||||
}
|
||||
|
||||
.font_22 {
|
||||
font-size: px2rem(22);
|
||||
}
|
||||
|
||||
.font_24 {
|
||||
font-size: px2rem(24);
|
||||
}
|
||||
|
||||
.font_26 {
|
||||
font-size: px2rem(26);
|
||||
}
|
||||
|
||||
.font_28 {
|
||||
font-size: px2rem(28);
|
||||
}
|
||||
|
||||
.font_30 {
|
||||
font-size: px2rem(30);
|
||||
}
|
||||
|
||||
.font_32 {
|
||||
font-size: px2rem(32);
|
||||
}
|
||||
|
||||
.font_34 {
|
||||
font-size: px2rem(34);
|
||||
}
|
||||
|
||||
.font_36 {
|
||||
font-size: px2rem(36);
|
||||
}
|
||||
|
||||
.font_38 {
|
||||
font-size: px2rem(38);
|
||||
}
|
||||
|
||||
.font_40 {
|
||||
font-size: px2rem(40);
|
||||
}
|
||||
|
||||
.font_42 {
|
||||
font-size: px2rem(42);
|
||||
}
|
||||
|
||||
.font_44 {
|
||||
font-size: px2rem(44);
|
||||
}
|
||||
|
||||
.font_46 {
|
||||
font-size: px2rem(46);
|
||||
}
|
||||
|
||||
.font_48 {
|
||||
font-size: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-pt-4 {
|
||||
padding-top: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-pt-6 {
|
||||
padding-top: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-pt-8 {
|
||||
padding-top: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-pt-10 {
|
||||
padding-top: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-pt-12 {
|
||||
padding-top: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-pt-14 {
|
||||
padding-top: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-pt-16 {
|
||||
padding-top: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-pt-18 {
|
||||
padding-top: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-pt-20 {
|
||||
padding-top: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-pt-22 {
|
||||
padding-top: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-pt-24 {
|
||||
padding-top: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-pt-26 {
|
||||
padding-top: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-pt-28 {
|
||||
padding-top: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-pt-30 {
|
||||
padding-top: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-pt-32 {
|
||||
padding-top: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-pt-36 {
|
||||
padding-top: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-pt-40 {
|
||||
padding-top: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-pr-4 {
|
||||
padding-right: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-pr-6 {
|
||||
padding-right: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-pr-8 {
|
||||
padding-right: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-pr-10 {
|
||||
padding-right: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-pr-12 {
|
||||
padding-right: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-pr-14 {
|
||||
padding-right: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-pr-16 {
|
||||
padding-right: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-pr-18 {
|
||||
padding-right: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-pr-20 {
|
||||
padding-right: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-pr-22 {
|
||||
padding-right: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-pr-24 {
|
||||
padding-right: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-pr-26 {
|
||||
padding-right: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-pr-28 {
|
||||
padding-right: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-pr-30 {
|
||||
padding-right: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-pr-32 {
|
||||
padding-right: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-pr-36 {
|
||||
padding-right: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-pr-40 {
|
||||
padding-right: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-pb-4 {
|
||||
padding-bottom: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-pb-6 {
|
||||
padding-bottom: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-pb-8 {
|
||||
padding-bottom: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-pb-10 {
|
||||
padding-bottom: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-pb-12 {
|
||||
padding-bottom: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-pb-14 {
|
||||
padding-bottom: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-pb-16 {
|
||||
padding-bottom: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-pb-18 {
|
||||
padding-bottom: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-pb-20 {
|
||||
padding-bottom: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-pb-22 {
|
||||
padding-bottom: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-pb-24 {
|
||||
padding-bottom: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-pb-26 {
|
||||
padding-bottom: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-pb-28 {
|
||||
padding-bottom: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-pb-30 {
|
||||
padding-bottom: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-pb-32 {
|
||||
padding-bottom: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-pb-36 {
|
||||
padding-bottom: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-pb-40 {
|
||||
padding-bottom: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-pl-4 {
|
||||
padding-left: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-pl-6 {
|
||||
padding-left: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-pl-8 {
|
||||
padding-left: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-pl-10 {
|
||||
padding-left: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-pl-12 {
|
||||
padding-left: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-pl-14 {
|
||||
padding-left: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-pl-16 {
|
||||
padding-left: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-pl-18 {
|
||||
padding-left: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-pl-20 {
|
||||
padding-left: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-pl-22 {
|
||||
padding-left: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-pl-24 {
|
||||
padding-left: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-pl-26 {
|
||||
padding-left: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-pl-28 {
|
||||
padding-left: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-pl-30 {
|
||||
padding-left: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-pl-32 {
|
||||
padding-left: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-pl-36 {
|
||||
padding-left: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-pl-40 {
|
||||
padding-left: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-mt-4 {
|
||||
margin-top: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-mt-6 {
|
||||
margin-top: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-mt-8 {
|
||||
margin-top: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-mt-10 {
|
||||
margin-top: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-mt-12 {
|
||||
margin-top: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-mt-14 {
|
||||
margin-top: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-mt-16 {
|
||||
margin-top: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-mt-18 {
|
||||
margin-top: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-mt-20 {
|
||||
margin-top: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-mt-22 {
|
||||
margin-top: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-mt-24 {
|
||||
margin-top: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-mt-26 {
|
||||
margin-top: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-mt-28 {
|
||||
margin-top: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-mt-30 {
|
||||
margin-top: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-mt-32 {
|
||||
margin-top: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-mt-36 {
|
||||
margin-top: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-mt-40 {
|
||||
margin-top: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-mr-4 {
|
||||
margin-right: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-mr-6 {
|
||||
margin-right: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-mr-8 {
|
||||
margin-right: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-mr-10 {
|
||||
margin-right: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-mr-12 {
|
||||
margin-right: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-mr-14 {
|
||||
margin-right: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-mr-16 {
|
||||
margin-right: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-mr-18 {
|
||||
margin-right: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-mr-20 {
|
||||
margin-right: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-mr-22 {
|
||||
margin-right: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-mr-24 {
|
||||
margin-right: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-mr-26 {
|
||||
margin-right: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-mr-28 {
|
||||
margin-right: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-mr-30 {
|
||||
margin-right: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-mr-32 {
|
||||
margin-right: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-mr-36 {
|
||||
margin-right: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-mr-40 {
|
||||
margin-right: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-mb-4 {
|
||||
margin-bottom: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-mb-6 {
|
||||
margin-bottom: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-mb-8 {
|
||||
margin-bottom: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-mb-10 {
|
||||
margin-bottom: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-mb-12 {
|
||||
margin-bottom: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-mb-14 {
|
||||
margin-bottom: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-mb-16 {
|
||||
margin-bottom: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-mb-18 {
|
||||
margin-bottom: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-mb-20 {
|
||||
margin-bottom: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-mb-22 {
|
||||
margin-bottom: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-mb-24 {
|
||||
margin-bottom: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-mb-26 {
|
||||
margin-bottom: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-mb-28 {
|
||||
margin-bottom: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-mb-30 {
|
||||
margin-bottom: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-mb-32 {
|
||||
margin-bottom: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-mb-36 {
|
||||
margin-bottom: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-mb-40 {
|
||||
margin-bottom: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-ml-4 {
|
||||
margin-left: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-ml-6 {
|
||||
margin-left: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-ml-8 {
|
||||
margin-left: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-ml-10 {
|
||||
margin-left: px2rem(10);
|
||||
}
|
||||
|
||||
.ui-ml-12 {
|
||||
margin-left: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-ml-14 {
|
||||
margin-left: px2rem(14);
|
||||
}
|
||||
|
||||
.ui-ml-16 {
|
||||
margin-left: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-ml-18 {
|
||||
margin-left: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-ml-20 {
|
||||
margin-left: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-ml-22 {
|
||||
margin-left: px2rem(22);
|
||||
}
|
||||
|
||||
.ui-ml-24 {
|
||||
margin-left: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-ml-26 {
|
||||
margin-left: px2rem(26);
|
||||
}
|
||||
|
||||
.ui-ml-28 {
|
||||
margin-left: px2rem(28);
|
||||
}
|
||||
|
||||
.ui-ml-30 {
|
||||
margin-left: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-ml-32 {
|
||||
margin-left: px2rem(32);
|
||||
}
|
||||
|
||||
.ui-ml-36 {
|
||||
margin-left: px2rem(36);
|
||||
}
|
||||
|
||||
.ui-ml-40 {
|
||||
margin-left: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-suspension-box {
|
||||
position: fixed;
|
||||
right: px2rem(20);
|
||||
bottom: px2rem(166);
|
||||
z-index: 22;
|
||||
}
|
||||
|
||||
.ui-mgt-entrance {
|
||||
width: px2rem(140);
|
||||
height: px2rem(140);
|
||||
display: block;
|
||||
margin-top: px2rem(20);
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100vh;
|
||||
transform: translate(0);
|
||||
}
|
||||
|
||||
/* 滚动条凹槽的颜色,还可以设置边框属性 */
|
||||
*::-webkit-scrollbar-track-piece {
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 2em;
|
||||
}
|
||||
|
||||
/* 滚动条 */
|
||||
*::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
129
src/styles/func.scss
Normal file
129
src/styles/func.scss
Normal file
@ -0,0 +1,129 @@
|
||||
@use 'sass:meta';
|
||||
|
||||
@function rpx($value) {
|
||||
@return $value * 1rpx;
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击文本状态
|
||||
*/
|
||||
@mixin click-text-active($color: rgba(0, 0, 0, 0.2)) {
|
||||
&:active {
|
||||
color: $color;
|
||||
transition: color 0.01s;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $color
|
||||
* 点击背景状态
|
||||
*/
|
||||
@mixin click-bg-active($color: rgba(0, 0, 0, 0.06)) {
|
||||
&:active {
|
||||
background-color: $color;
|
||||
transition: background-color 0.01s;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $rpx
|
||||
* 将元素设置成圆形
|
||||
*/
|
||||
@mixin el-to-circle($rpx) {
|
||||
width: rpx($rpx);
|
||||
height: rpx($rpx);
|
||||
border-radius: rpx($rpx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 绝对定位居中显示
|
||||
*/
|
||||
@mixin position-center() {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description flex布局垂直水平居中
|
||||
*/
|
||||
@mixin flex-center($args...) {
|
||||
@each $key, $value in meta.keywords($args) {
|
||||
& {
|
||||
#{$key}: $value;
|
||||
}
|
||||
}
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 多行文本省略号
|
||||
*/
|
||||
@mixin text-ellipsis($line: 1) {
|
||||
@if ($line == 1) {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 三角气泡框
|
||||
*/
|
||||
@mixin popover($placement, $args...) {
|
||||
@each $key, $value in meta.keywords($args) {
|
||||
&::after {
|
||||
#{$key}: $value;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
color: #fff;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 6px;
|
||||
content: '';
|
||||
}
|
||||
|
||||
&::after {
|
||||
@if ($placement == 'top') {
|
||||
border-bottom-width: 0;
|
||||
border-top-color: currentColor;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 100%);
|
||||
}
|
||||
@if ($placement == 'bottom') {
|
||||
border-top-width: 0;
|
||||
border-bottom-color: currentColor;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -100%);
|
||||
}
|
||||
@if ($placement == 'left') {
|
||||
border-right-width: 0;
|
||||
border-left-color: currentColor;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translate(100%, -50%);
|
||||
}
|
||||
@if ($placement == 'right') {
|
||||
border-left-width: 0;
|
||||
border-right-color: currentColor;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translate(-100%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
168
src/styles/rem/css/rem.css
Normal file
168
src/styles/rem/css/rem.css
Normal file
@ -0,0 +1,168 @@
|
||||
.f-p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html body {
|
||||
min-width: 320px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (-webkit-device-pixel-ratio: 2) {
|
||||
html body {
|
||||
min-width: 640px;
|
||||
}
|
||||
}
|
||||
@media (-webkit-device-pixel-ratio: 3) {
|
||||
html body {
|
||||
min-width: 960px;
|
||||
}
|
||||
}
|
||||
|
||||
html body[data-content-max] {
|
||||
max-width: 540px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (-webkit-device-pixel-ratio: 2) {
|
||||
html body[data-content-max] {
|
||||
max-width: 1080px;
|
||||
}
|
||||
}
|
||||
@media (-webkit-device-pixel-ratio: 3) {
|
||||
html body[data-content-max] {
|
||||
max-width: 1620px;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-dpr='1'] body {
|
||||
min-width: 320px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 0.3733333333rem;
|
||||
background-color: #f8f8f8;
|
||||
border-width: 45px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 4rem;
|
||||
line-height: 4rem;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 2.6666666667rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav ul .icon {
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
margin-bottom: 0.2666666667rem;
|
||||
line-height: 1.6rem;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 0.2666666667rem;
|
||||
}
|
||||
|
||||
main h3 {
|
||||
position: relative;
|
||||
margin-top: 0.6666666667rem;
|
||||
margin-left: 0.3466666667rem;
|
||||
font-size: 0.4rem;
|
||||
}
|
||||
|
||||
main h3::before {
|
||||
position: absolute;
|
||||
left: -0.2666666667rem;
|
||||
width: 0.16rem;
|
||||
height: 100%;
|
||||
background-color: #fc8200;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.info-items {
|
||||
margin-top: 0.2666666667rem;
|
||||
margin-bottom: 0.2666666667rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
padding: 0.4rem;
|
||||
padding-left: 0;
|
||||
margin-top: 0.2666666667rem;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
min-width: 1.6rem;
|
||||
text-align: center;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.info-item input {
|
||||
width: 100%;
|
||||
font-size: 0.3733333333rem;
|
||||
border: none;
|
||||
outline: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
.info-item textarea {
|
||||
width: 100%;
|
||||
height: 3.3333333333rem;
|
||||
padding: 0.2666666667rem;
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 0.3733333333rem;
|
||||
-webkit-text-size-adjust: none;
|
||||
text-size-adjust: none;
|
||||
border: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
.info-confirm {
|
||||
margin-bottom: 0.5333333333rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-confirm__btn {
|
||||
display: inline-block;
|
||||
width: 2.6666666667rem;
|
||||
height: 1.0666666667rem;
|
||||
margin-top: 1.0666666667rem;
|
||||
line-height: 1.0666666667rem;
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
background-color: #fc8200;
|
||||
}
|
||||
|
||||
footer {
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
7
src/styles/rem/css/rem.css.map
Normal file
7
src/styles/rem/css/rem.css.map
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"mappings": "AAIA,MAAO,CACH,OAAO,CAAE,YAAY,CAGzB,SACK,CACD,MAAM,CAAE,CAAC,CACT,OAAO,CAAE,CAAC,CCsBV,SAAK,CAgBL,YAAY,CAAE,IAAI,CAClB,WAAW,CAAE,IAAI,CACjB,SAAS,CA1CM,KAAK,CA4CpB,sCAAuC,CApBvC,SAAK,CAqBD,SAAS,CAAE,KAAqB,EAGpC,sCAAuC,CAxBvC,SAAK,CAyBD,SAAS,CAAE,KAAqB,EAtBhC,2BAAoB,CA4BxB,YAAY,CAAE,IAAI,CAClB,WAAW,CAAE,IAAI,CACjB,SAAS,CAvDM,KAAK,CAyDpB,sCAAuC,CAhCnC,2BAAoB,CAiCpB,SAAS,CAAE,MAAqB,EAGpC,sCAAuC,CApCnC,2BAAoB,CAqCpB,SAAS,CAAE,MAAqB,EA/BpC,uBAAqB,CACjB,SAAS,CAlCE,KAAK,CDSxB,IAAK,CAED,YAAY,CCQJ,IAAmC,CDN3C,gBAAgB,CAAE,OAAO,CACzB,SAAS,CCAD,cAAmC,CDC3C,WAAW,CAAE,iBAAiB,CAGlC,UAAW,CACP,gBAAgB,CAAE,IAAI,CAG1B,MAAO,CACH,MAAM,CCTE,IAAmC,CDU3C,WAAW,CCVH,IAAmC,CDW3C,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,OAAO,CAG7B,MAAO,CACH,OAAO,CAAE,IAAI,CACb,eAAe,CAAE,YAAY,CAC7B,OAAO,CAAE,CAAC,CAEV,SAAG,CACC,OAAO,CAAE,IAAI,CACb,SAAS,CAAE,IAAI,CACf,KAAK,CCvBD,eAAmC,CDwBvC,eAAe,CAAE,MAAM,CAG3B,YAAM,CACF,aAAa,CC5BT,cAAmC,CD6BvC,KAAK,CC7BD,MAAmC,CD8BvC,MAAM,CC9BF,MAAmC,CD+BvC,WAAW,CC/BP,MAAmC,CDgCvC,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,OAAO,CAIjC,IAAK,CACD,OAAO,CCtCC,cAAmC,CDwC3C,OAAG,CACC,QAAQ,CAAE,QAAQ,CAClB,UAAU,CC1CN,cAAmC,CD2CvC,WAAW,CC3CP,cAAmC,CD4CvC,SAAS,CC5CL,KAAmC,CDkDvC,cAAS,CACL,OAAO,CAAE,EAAE,CACX,QAAQ,CAAE,QAAQ,CAClB,IAAI,CCrDJ,eAAmC,CDsDnC,KAAK,CCtDL,MAAmC,CDuDnC,MAAM,CAAE,IAAI,CACZ,gBAAgB,CAAE,OAAO,CAKrC,WAAY,CACR,UAAU,CC9DF,cAAmC,CD+D3C,aAAa,CC/DL,cAAmC,CDkE/C,UAAW,CACP,UAAU,CCnEF,cAAmC,CDoE3C,OAAO,CCpEC,KAAmC,CDqE3C,YAAY,CAAE,CAAC,CACf,MAAM,CAAE,cAAc,CAEtB,OAAO,CAAE,IAAI,CAEb,eAAK,CACD,SAAS,CC3EL,MAAmC,CD4EvC,UAAU,CAAE,MAAM,CAClB,YAAY,CAAE,cAAc,CAGhC,gBAAM,CACF,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,SAAS,CCnFL,cAAmC,CDoFvC,WAAW,CAAE,OAAO,CACpB,OAAO,CAAE,IAAI,CAGjB,mBAAS,CACL,OAAO,CCzFH,cAAmC,CD0FvC,KAAK,CAAE,IAAI,CACX,MAAM,CAAE,IAAI,CACZ,MAAM,CC5FF,eAAmC,CD6FvC,SAAS,CC7FL,cAAmC,CD8FvC,WAAW,CAAE,iBAAiB,CAC9B,WAAW,CAAE,OAAO,CACpB,wBAAwB,CAAE,IAAI,CAC9B,gBAAgB,CAAE,IAAI,CAI9B,aAAc,CACV,aAAa,CCtGL,cAAmC,CDuG3C,UAAU,CAAE,MAAM,CAElB,kBAAO,CACH,OAAO,CAAE,YAAY,CACrB,UAAU,CC3GN,eAAmC,CD4GvC,KAAK,CC5GD,eAAmC,CD6GvC,MAAM,CC7GF,eAAmC,CD8GvC,WAAW,CC9GP,eAAmC,CD+GvC,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,OAAO,CACzB,eAAe,CAAE,eAAe,CAChC,KAAK,CAAE,eAAe,CAK9B,MAAO,CACH,MAAM,CCxHE,IAAmC,CDyH3C,WAAW,CCzHH,IAAmC,CD0H3C,UAAU,CAAE,MAAM,CAClB,gBAAgB,CAAE,OAAO",
|
||||
"sources": ["../scss/rem.scss","../scss/_util.scss"],
|
||||
"names": [],
|
||||
"file": "rem.css"
|
||||
}
|
||||
61
src/styles/rem/index.html
Normal file
61
src/styles/rem/index.html
Normal file
@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>REM布局</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta lang="zh-CN" />
|
||||
<meta
|
||||
name="viewport"
|
||||
data-content-max
|
||||
content="width=device-width,initial-scale=1,user-scalable=no"
|
||||
/>
|
||||
<link rel="stylesheet" href="./css/rem.css" />
|
||||
<script src="./js/rem.min.js"></script>
|
||||
<!-- <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script> -->
|
||||
</head>
|
||||
|
||||
<body data-content-max>
|
||||
<section class="container">
|
||||
<header>375 * 150</header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h3>填写信息</h3>
|
||||
<div class="info-items">
|
||||
<p class="info-item">
|
||||
<span>姓名</span>
|
||||
<input type="text" class="info-item__name" placeholder="请填写姓名" />
|
||||
</p>
|
||||
<p class="info-item">
|
||||
<span>手机</span>
|
||||
<input type="number" class="info-item__tel" placeholder="请填写手机号" />
|
||||
</p>
|
||||
</div>
|
||||
<h3>个人介绍</h3>
|
||||
<div class="info-items">
|
||||
<p class="info-item f-p-0">
|
||||
<textarea class="info-item__intro" placeholder="请填写一段简要的自我介绍"></textarea>
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-confirm">
|
||||
<a href="javascript:;" class="info-confirm__btn">确认</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer>375 * 75</footer>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
70
src/styles/rem/js/rem.js
Normal file
70
src/styles/rem/js/rem.js
Normal file
@ -0,0 +1,70 @@
|
||||
!(function () {
|
||||
let docElem = document.documentElement,
|
||||
metaElem = document.querySelector('meta[name="viewport"]'),
|
||||
dpr = window.devicePixelRatio || 1,
|
||||
// 将页面分为10块
|
||||
blocks = 10,
|
||||
// 需要限制的最小宽度
|
||||
defaultMinWidth = 320,
|
||||
// 需要限制的最大宽度
|
||||
defaultMaxWidth = 540,
|
||||
// 计算的基准值
|
||||
calcMaxWidth = 9999999;
|
||||
|
||||
if (!metaElem) {
|
||||
metaElem = initMetaViewport();
|
||||
}
|
||||
|
||||
if (metaElem.getAttribute('data-content-max') !== null) {
|
||||
calcMaxWidth = defaultMaxWidth;
|
||||
}
|
||||
|
||||
// 确保meta[name="viewport"]存在
|
||||
function initMetaViewport() {
|
||||
const meta = document.createElement('meta');
|
||||
|
||||
meta.setAttribute('name', 'viewport');
|
||||
meta.setAttribute('content', 'width=device-width,initial-scale=1,user-scalable=no');
|
||||
document.head.appendChild(meta);
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
// 大部分dpr为2以下的安卓机型不识别scale,需设置不缩放
|
||||
if (navigator.appVersion.match(/android/gi) && dpr <= 2) {
|
||||
dpr = 1;
|
||||
}
|
||||
|
||||
setScale(dpr);
|
||||
|
||||
// 企业QQ设置了scale后,不能完全识别scale(此时clientWidth未收到缩放的影响而翻倍),需设置不缩放
|
||||
if (navigator.appVersion.match(/qq\//gi) && docElem.clientWidth <= 360) {
|
||||
dpr = 1;
|
||||
setScale(dpr);
|
||||
}
|
||||
|
||||
docElem.setAttribute('data-dpr', dpr);
|
||||
|
||||
// 设置缩放
|
||||
function setScale(dpr) {
|
||||
metaElem.setAttribute('content', `initial-scale=${1 / dpr},maximum-scale=${1 / dpr},minimum-scale=${1 / dpr},user-scalable=no`);
|
||||
}
|
||||
|
||||
// 设置docElem字体大小
|
||||
function setFontSize() {
|
||||
let clientWidth = docElem.clientWidth;
|
||||
|
||||
clientWidth = Math.max(clientWidth, defaultMinWidth * dpr);
|
||||
|
||||
// 调整计算基准值
|
||||
if (calcMaxWidth === defaultMaxWidth) {
|
||||
clientWidth = Math.min(clientWidth, defaultMaxWidth * dpr);
|
||||
}
|
||||
|
||||
docElem.style.fontSize = `${clientWidth / blocks}px`;
|
||||
}
|
||||
|
||||
setFontSize();
|
||||
|
||||
window.addEventListener(window.orientationchange ? 'orientationchange' : 'resize', setFontSize, false);
|
||||
})();
|
||||
44
src/styles/rem/js/rem.min.js
vendored
Normal file
44
src/styles/rem/js/rem.min.js
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
!(function () {
|
||||
let c = document.documentElement,
|
||||
j = document.querySelector('meta[name="viewport"]'),
|
||||
h = window.devicePixelRatio || 1,
|
||||
a = 10,
|
||||
f = 320,
|
||||
b = 540,
|
||||
i = 9999999;
|
||||
if (!j) {
|
||||
j = e();
|
||||
}
|
||||
if (j.getAttribute('data-content-max') !== null) {
|
||||
i = b;
|
||||
}
|
||||
function e() {
|
||||
const k = document.createElement('meta');
|
||||
k.setAttribute('name', 'viewport');
|
||||
k.setAttribute('content', 'width=device-width,initial-scale=1,user-scalable=no');
|
||||
document.head.appendChild(k);
|
||||
return k;
|
||||
}
|
||||
if (navigator.appVersion.match(/android/gi) && h <= 2) {
|
||||
h = 1;
|
||||
}
|
||||
g(h);
|
||||
if (navigator.appVersion.match(/qq\//gi) && c.clientWidth <= 360) {
|
||||
h = 1;
|
||||
g(h);
|
||||
}
|
||||
c.setAttribute('data-dpr', h);
|
||||
function g(k) {
|
||||
j.setAttribute('content', `initial-scale=${1 / k},maximum-scale=${1 / k},minimum-scale=${1 / k},user-scalable=no`);
|
||||
}
|
||||
function d() {
|
||||
let k = c.clientWidth;
|
||||
k = Math.max(k, f * h);
|
||||
if (i === b) {
|
||||
k = Math.min(k, b * h);
|
||||
}
|
||||
c.style.fontSize = `${k / a}px`;
|
||||
}
|
||||
d();
|
||||
window.addEventListener(window.orientationchange ? 'orientationchange' : 'resize', d, false);
|
||||
})();
|
||||
95
src/styles/rem/scss/_util.scss
Normal file
95
src/styles/rem/scss/_util.scss
Normal file
@ -0,0 +1,95 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@use 'sass:math';
|
||||
|
||||
/* 移动端页面设计稿宽度 */
|
||||
$design-width: 750;
|
||||
|
||||
/* 移动端页面设计稿dpr基准值 */
|
||||
$design-dpr: 2;
|
||||
|
||||
/* 将移动端页面分为10块 */
|
||||
$blocks: 10;
|
||||
|
||||
/* 缩放所支持的设备最小宽度 */
|
||||
$min-device-width: 320px;
|
||||
|
||||
/* 缩放所支持的设备最大宽度 */
|
||||
$max-device-width: 540px;
|
||||
|
||||
/*
|
||||
rem与px对应关系,1rem代表在JS中设置的html font-size值(为一块的宽度),$rem即为$px对应占多少块
|
||||
|
||||
$px $rem
|
||||
------------- === ------------
|
||||
$design-width $blocks
|
||||
*/
|
||||
|
||||
/* 单位px转化为rem */
|
||||
@function px2rem($px) {
|
||||
@return #{math.div($px, $design-width) * $blocks}rem;
|
||||
}
|
||||
|
||||
/* 单位rem转化为px,可用于根据rem单位快速计算原px */
|
||||
@function rem2px($rem) {
|
||||
@return #{math.div($rem, $blocks) * $design-width}px;
|
||||
}
|
||||
|
||||
/* html根的宽度定义 */
|
||||
@mixin root-width() {
|
||||
body {
|
||||
@include container-min-width();
|
||||
|
||||
&[data-content-max] {
|
||||
@include container-max-width();
|
||||
}
|
||||
}
|
||||
|
||||
/* 某些机型虽然设备dpr大于1,但识别不了scale缩放,这里需要重新设置最小宽度防止出现横向滚动条 */
|
||||
&[data-dpr='1'] body {
|
||||
min-width: $min-device-width;
|
||||
}
|
||||
}
|
||||
|
||||
/* 设置容器拉伸的最小宽度 */
|
||||
@mixin container-min-width() {
|
||||
min-width: $min-device-width;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
|
||||
@media (-webkit-device-pixel-ratio: 2) {
|
||||
min-width: $min-device-width * 2;
|
||||
}
|
||||
|
||||
@media (-webkit-device-pixel-ratio: 3) {
|
||||
min-width: $min-device-width * 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* 设置容器拉伸的最大宽度 */
|
||||
@mixin container-max-width() {
|
||||
max-width: $max-device-width;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
|
||||
@media (-webkit-device-pixel-ratio: 2) {
|
||||
max-width: $max-device-width * 2;
|
||||
}
|
||||
|
||||
@media (-webkit-device-pixel-ratio: 3) {
|
||||
max-width: $max-device-width * 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* 设置字体大小,不使用rem单位, 根据dpr值分段调整 */
|
||||
@mixin font-size($fontSize) {
|
||||
font-size: $fontSize / $design-dpr;
|
||||
|
||||
[data-dpr='2'] & {
|
||||
font-size: $fontSize / $design-dpr * 2;
|
||||
}
|
||||
|
||||
[data-dpr='3'] & {
|
||||
font-size: $fontSize / $design-dpr * 3;
|
||||
}
|
||||
}
|
||||
146
src/styles/rem/scss/rem.scss
Normal file
146
src/styles/rem/scss/rem.scss
Normal file
@ -0,0 +1,146 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@import './util';
|
||||
|
||||
.f-p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
@include root-width();
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: px2rem(28);
|
||||
background-color: #f8f8f8;
|
||||
|
||||
/* rem2px的使用方式,仅用于临时计算 */
|
||||
border-width: rem2px(0.6);
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
header {
|
||||
height: px2rem(300);
|
||||
line-height: px2rem(300);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: px2rem(200);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: px2rem(120);
|
||||
height: px2rem(120);
|
||||
margin-bottom: px2rem(20);
|
||||
line-height: px2rem(120);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: px2rem(20);
|
||||
|
||||
h3 {
|
||||
position: relative;
|
||||
margin-top: px2rem(50);
|
||||
margin-left: px2rem(26);
|
||||
font-size: px2rem(30);
|
||||
|
||||
/* 字体也可以选择不使用rem
|
||||
@include font-size(30px);
|
||||
*/
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: px2rem(-20);
|
||||
width: px2rem(12);
|
||||
height: 100%;
|
||||
background-color: #fc8200;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-items {
|
||||
margin-top: px2rem(20);
|
||||
margin-bottom: px2rem(20);
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
padding: px2rem(30);
|
||||
padding-left: 0;
|
||||
margin-top: px2rem(20);
|
||||
border: 1px solid #ddd;
|
||||
|
||||
span {
|
||||
min-width: px2rem(120);
|
||||
text-align: center;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
font-size: px2rem(28);
|
||||
border: none;
|
||||
outline: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: px2rem(250);
|
||||
padding: px2rem(20);
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: px2rem(28);
|
||||
-webkit-text-size-adjust: none;
|
||||
text-size-adjust: none;
|
||||
border: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
}
|
||||
|
||||
.info-confirm {
|
||||
margin-bottom: px2rem(40);
|
||||
text-align: center;
|
||||
|
||||
&__btn {
|
||||
display: inline-block;
|
||||
width: px2rem(200);
|
||||
height: px2rem(80);
|
||||
margin-top: px2rem(80);
|
||||
line-height: px2rem(80);
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
background-color: #fc8200;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
height: px2rem(150);
|
||||
line-height: px2rem(150);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
230
src/styles/vw-rem/_border.scss
Normal file
230
src/styles/vw-rem/_border.scss
Normal file
@ -0,0 +1,230 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/**
|
||||
* 获取边框某项对应的值
|
||||
* @example getBorderItemValue(10px, 2)
|
||||
* @param {string|list} $item 某一项或多个项的列表
|
||||
* @param {number} $index 下标
|
||||
* @return {string} 项值
|
||||
*/
|
||||
@function getBorderItemValue($item, $index) {
|
||||
@if (type-of($item) == list) {
|
||||
@if ($index > length($item)) {
|
||||
$index: 1;
|
||||
}
|
||||
|
||||
@return nth($item, $index);
|
||||
} @else {
|
||||
@return $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为百分比
|
||||
* @param {number} $value 值
|
||||
* @return {boolean} 是否为百分比
|
||||
*/
|
||||
@function is-percentage($value) {
|
||||
@return type-of($value) == number and unit($value) == '%';
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框圆角,支持单个值与多个值,在高清设备下px圆角加倍
|
||||
* @param {number|list} $radius 圆角值
|
||||
* @param {number} $ratio 设备像素比
|
||||
*/
|
||||
@mixin border-radius($radius: 0, $ratio: 1) {
|
||||
$border-radius-corner: (top-left, top-right, bottom-right, bottom-left);
|
||||
|
||||
/* 列表 按照四个角的顺序匹配 */
|
||||
@if (type-of($radius) == list) {
|
||||
@for $i from 1 through length($radius) {
|
||||
$item: nth($radius, $i);
|
||||
$corner: nth($border-radius-corner, $i);
|
||||
|
||||
/* 普通设备,或者为百分比则直接使用圆角值 */
|
||||
@if $ratio == 1 or is-percentage($item) {
|
||||
border-#{$corner}-radius: $item;
|
||||
}
|
||||
|
||||
/* 否则翻$ratio倍 */
|
||||
@else {
|
||||
border-#{$corner}-radius: $item * $ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 单个值 */
|
||||
@else {
|
||||
@if $ratio == 1 or is-percentage($radius) {
|
||||
border-radius: $radius;
|
||||
} @else {
|
||||
border-radius: $radius * $ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 元素边框
|
||||
* @param {string|list} $direction: all 为all或列表时表示多个方向的边框,否则为单个边框
|
||||
* @param {string|list} $size: 1px 边框尺寸,为列表时表将按照direction的顺序取值
|
||||
* @param {string|list} $style: solid 边框样式,高清设备下仅支持solid,同上
|
||||
* @param {string|list} $color: #ddd 边框颜色,同上
|
||||
* @param {string} $position: relative 元素定位方式,一般为relative即可
|
||||
* @param {string} $radius: 0 边框圆角
|
||||
*/
|
||||
@mixin border(
|
||||
$direction: all,
|
||||
$size: 1px,
|
||||
$style: solid,
|
||||
$color: #ddd,
|
||||
$position: relative,
|
||||
$radius: 0
|
||||
) {
|
||||
/* 多个边框 */
|
||||
@if $direction == all or type-of($direction) == list {
|
||||
/* 普通设备 */
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
@include border-radius($radius);
|
||||
|
||||
@if $direction == all {
|
||||
border: $size $style $color;
|
||||
} @else {
|
||||
@for $i from 1 through length($direction) {
|
||||
$item: nth($direction, $i);
|
||||
|
||||
border-#{$item}: getborderitemvalue($size, $i)
|
||||
getborderitemvalue($style, $i)
|
||||
getborderitemvalue($color, $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 高清设备 */
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
@include border-multiple(
|
||||
$direction: $direction,
|
||||
$size: $size,
|
||||
$color: $color,
|
||||
$position: $position,
|
||||
$radius: $radius
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* 单个边框 */
|
||||
@else {
|
||||
/* 普通设备 */
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
border-#{$direction}: $size $style $color;
|
||||
}
|
||||
|
||||
/* 高清设备 */
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
@include border-single(
|
||||
$direction: $direction,
|
||||
$size: $size,
|
||||
$color: $color,
|
||||
$position: $position
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 实现1物理像素的单条边框线 */
|
||||
@mixin border-single($direction: bottom, $size: 1px, $color: #ddd, $position: relative) {
|
||||
position: $position;
|
||||
|
||||
&::after {
|
||||
/* 上下 */
|
||||
@if ($direction == top or $direction == bottom) {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: $size;
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 2) {
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 3) {
|
||||
-webkit-transform: scaleY(0.333333333333);
|
||||
transform: scaleY(0.333333333333);
|
||||
}
|
||||
}
|
||||
|
||||
/* 左右 */
|
||||
@else if ($direction == left or $direction == right) {
|
||||
top: 0;
|
||||
width: $size;
|
||||
height: 100%;
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 2) {
|
||||
-webkit-transform: scaleX(0.5);
|
||||
transform: scaleX(0.5);
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 3) {
|
||||
-webkit-transform: scaleX(0.333333333333);
|
||||
transform: scaleX(0.333333333333);
|
||||
}
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
background-color: $color;
|
||||
content: '';
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
#{$direction}: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 实现1物理像素的多条边框线 */
|
||||
@mixin border-multiple($direction: all, $size: 1px, $color: #ddd, $position: relative, $radius: 0) {
|
||||
@include border-radius($radius);
|
||||
|
||||
position: $position;
|
||||
|
||||
&::after {
|
||||
@if $direction == all {
|
||||
border: $size solid $color;
|
||||
} @else {
|
||||
@for $i from 1 through length($direction) {
|
||||
$item: nth($direction, $i);
|
||||
|
||||
border-#{$item}: getborderitemvalue($size, $i) solid getborderitemvalue($color, $i);
|
||||
}
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
transform-origin: top left;
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 2) {
|
||||
@include border-radius($radius, 2);
|
||||
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 3) {
|
||||
@include border-radius($radius, 3);
|
||||
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
-webkit-transform: scale(0.333333333333, 0.333333333333);
|
||||
transform: scale(0.333333333333, 0.333333333333);
|
||||
}
|
||||
}
|
||||
}
|
||||
115
src/styles/vw-rem/_util.scss
Normal file
115
src/styles/vw-rem/_util.scss
Normal file
@ -0,0 +1,115 @@
|
||||
@charset "UTF-8";
|
||||
@use 'sass:math';
|
||||
|
||||
/* 移动端页面设计稿宽度 */
|
||||
$design-width: 750;
|
||||
|
||||
/* 移动端页面设计稿dpr基准值 */
|
||||
$design-dpr: 2;
|
||||
|
||||
/* 将移动端页面分为10块 */
|
||||
$blocks: 10;
|
||||
|
||||
/* 缩放所支持的设备最小宽度 */
|
||||
$min-device-width: 320px;
|
||||
|
||||
/* 缩放所支持的设备最大宽度 */
|
||||
$max-device-width: 540px;
|
||||
|
||||
/*
|
||||
rem与px对应关系,1rem代表html font-size值(为一块的宽度),$rem即为$px对应占多少块
|
||||
|
||||
$px $rem
|
||||
------------- === ------------
|
||||
$design-width $blocks
|
||||
*/
|
||||
|
||||
/* html根元素的font-size定义,简单地将页面分为$blocks块,方便计算 */
|
||||
@mixin root-font-size() {
|
||||
font-size: math.div(100vw, $blocks);
|
||||
|
||||
/* 最小宽度定义 */
|
||||
@media screen and (max-width: $min-device-width) {
|
||||
font-size: math.div($min-device-width, $blocks);
|
||||
}
|
||||
|
||||
body {
|
||||
@include container-min-width();
|
||||
}
|
||||
|
||||
/* 最大宽度定义 */
|
||||
&[data-content-max] {
|
||||
@media screen and (min-width: $max-device-width) {
|
||||
font-size: math.div($max-device-width, $blocks);
|
||||
}
|
||||
|
||||
body[data-content-max] {
|
||||
@include container-max-width();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 单位px转化为rem */
|
||||
@function px2rem($px) {
|
||||
@return #{math.div($px, $design-width) * $blocks}rem;
|
||||
}
|
||||
|
||||
/* 单位rem转化为px,可用于根据rem单位快速计算原px */
|
||||
@function rem2px($rem) {
|
||||
@return #{math.div($px, $design-width) * $design-width}px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现固定宽高比
|
||||
* @param {string} $position: relative 定位方式
|
||||
* @param {string} $width: 100% 容器宽度
|
||||
* @param {string} $sub: null 容器的目标子元素
|
||||
* @param {number} $aspectX: 1 容器宽
|
||||
* @param {number} $aspectY: 1 容器高
|
||||
*/
|
||||
@mixin aspect-ratio($position: relative, $width: 100%, $sub: null, $aspectX: 1, $aspectY: 1) {
|
||||
@if $sub == null {
|
||||
$sub: '*';
|
||||
}
|
||||
|
||||
position: $position;
|
||||
width: $width;
|
||||
height: 0;
|
||||
padding-top: percentage($aspectY / $aspectX);
|
||||
overflow: hidden;
|
||||
|
||||
& > #{$sub} {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 设置容器拉伸的最小宽度 */
|
||||
@mixin container-min-width() {
|
||||
min-width: $min-device-width;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* 设置容器拉伸的最大宽度 */
|
||||
@mixin container-max-width() {
|
||||
max-width: $max-device-width;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* 设置字体大小,不使用rem单位, 根据dpr值分段调整 */
|
||||
@mixin font-size($fontSize) {
|
||||
font-size: $fontSize / $design-dpr;
|
||||
|
||||
[data-dpr='2'] & {
|
||||
font-size: $fontSize / $design-dpr * 2;
|
||||
}
|
||||
|
||||
[data-dpr='3'] & {
|
||||
font-size: $fontSize / $design-dpr * 3;
|
||||
}
|
||||
}
|
||||
577
src/styles/vw-rem/css/vw-rem.css
Normal file
577
src/styles/vw-rem/css/vw-rem.css
Normal file
@ -0,0 +1,577 @@
|
||||
.f-p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.f-border::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.f-border::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.f-border::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-bottom {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-bottom {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.f-border-bottom::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
pointer-events: none;
|
||||
background-color: #ddd;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-bottom::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.f-border-bottom::after {
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.f-border-bottom::after {
|
||||
-webkit-transform: scaleY(0.3333333333);
|
||||
transform: scaleY(0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-radius {
|
||||
border: 1px solid #ddd;
|
||||
border-top-right-radius: 20px;
|
||||
border-bottom-right-radius: 30px;
|
||||
border-bottom-left-radius: 40px;
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-radius {
|
||||
position: relative;
|
||||
border-top-right-radius: 20px;
|
||||
border-bottom-right-radius: 30px;
|
||||
border-bottom-left-radius: 40px;
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.f-border-radius::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.f-border-radius::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-top-right-radius: 40px;
|
||||
border-bottom-right-radius: 60px;
|
||||
border-bottom-left-radius: 80px;
|
||||
border-top-left-radius: 20px;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.f-border-radius::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-top-right-radius: 60px;
|
||||
border-bottom-right-radius: 90px;
|
||||
border-bottom-left-radius: 120px;
|
||||
border-top-left-radius: 30px;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 10vw;
|
||||
}
|
||||
|
||||
html body {
|
||||
min-width: 320px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 320px) {
|
||||
html {
|
||||
font-size: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-content-max] body[data-content-max] {
|
||||
max-width: 540px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 540px) {
|
||||
html[data-content-max] {
|
||||
font-size: 54px;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 0.3733333333rem;
|
||||
background-color: #f8f8f8;
|
||||
border-width: 45px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 4rem;
|
||||
line-height: 4rem;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 2.6666666667rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav ul .icon {
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
margin-bottom: 0.2666666667rem;
|
||||
line-height: 1.6rem;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 0.2666666667rem;
|
||||
}
|
||||
|
||||
main h3 {
|
||||
position: relative;
|
||||
margin-top: 0.6666666667rem;
|
||||
margin-left: 0.3466666667rem;
|
||||
font-size: 0.4rem;
|
||||
}
|
||||
|
||||
main h3::before {
|
||||
position: absolute;
|
||||
left: -0.2666666667rem;
|
||||
width: 0.16rem;
|
||||
height: 100%;
|
||||
background-color: #fc8200;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.info-items {
|
||||
margin-top: 0.2666666667rem;
|
||||
margin-bottom: 0.2666666667rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
padding: 0.4rem;
|
||||
padding-left: 0;
|
||||
margin-top: 0.2666666667rem;
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:not(.info-item__tel) {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:not(.info-item__tel) {
|
||||
position: relative;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.info-item:not(.info-item__tel)::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item:not(.info-item__tel)::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 100px;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item:not(.info-item__tel)::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 150px;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item.info-item__tel::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
pointer-events: none;
|
||||
background-color: #ddd;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel::after {
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item.info-item__tel::after {
|
||||
-webkit-transform: scaleY(0.3333333333);
|
||||
transform: scaleY(0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:only-of-type {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:only-of-type {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.info-item:only-of-type::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item:only-of-type::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item:only-of-type::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.hover {
|
||||
border-top: 3px dotted #0f0;
|
||||
border-right: 2px dotted #ddd;
|
||||
border-bottom: 1px dotted #0f0;
|
||||
border-left: 3px dotted #0f0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.hover {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.info-item.hover::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border-top: 3px solid #0f0;
|
||||
border-right: 2px solid #ddd;
|
||||
border-bottom: 1px solid #0f0;
|
||||
border-left: 3px solid #0f0;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item.hover::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item.hover::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
min-width: 1.6rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item span::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background-color: #ddd;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item span::after {
|
||||
-webkit-transform: scaleX(0.5);
|
||||
transform: scaleX(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item span::after {
|
||||
-webkit-transform: scaleX(0.3333333333);
|
||||
transform: scaleX(0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span.hover {
|
||||
border-right: 5px solid #0f0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span.hover {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item span.hover::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background-color: #0f0;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span.hover::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item span.hover::after {
|
||||
-webkit-transform: scaleX(0.5);
|
||||
transform: scaleX(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item span.hover::after {
|
||||
-webkit-transform: scaleX(0.3333333333);
|
||||
transform: scaleX(0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
.info-item input {
|
||||
width: 100%;
|
||||
font-size: 0.3733333333rem;
|
||||
border: none;
|
||||
outline: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
.info-item textarea {
|
||||
width: 100%;
|
||||
height: 3.3333333333rem;
|
||||
padding: 0.2666666667rem;
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 0.3733333333rem;
|
||||
-webkit-text-size-adjust: none;
|
||||
text-size-adjust: none;
|
||||
border: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
.info-confirm {
|
||||
margin-bottom: 0.5333333333rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-confirm__btn {
|
||||
display: inline-block;
|
||||
width: 2.6666666667rem;
|
||||
height: 1.0666666667rem;
|
||||
margin-top: 1.0666666667rem;
|
||||
line-height: 1.0666666667rem;
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
background-color: #fc8200;
|
||||
}
|
||||
|
||||
footer {
|
||||
height: 2rem;
|
||||
line-height: 2rem;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
7
src/styles/vw-rem/css/vw-rem.css.map
Normal file
7
src/styles/vw-rem/css/vw-rem.css.map
Normal file
File diff suppressed because one or more lines are too long
58
src/styles/vw-rem/index.html
Normal file
58
src/styles/vw-rem/index.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html data-content-max>
|
||||
<head>
|
||||
<title>VW-REM布局</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta lang="zh-CN" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
|
||||
<link rel="stylesheet" href="./css/vw-rem.css" />
|
||||
</head>
|
||||
|
||||
<body data-content-max>
|
||||
<section class="container">
|
||||
<!-- 此处为固定宽高比的例子 -->
|
||||
<header class="header">
|
||||
<div class="header-content">375 * 150</div>
|
||||
</header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon f-border-radius">圆角</span>
|
||||
<span class="f-border">导航入口</span>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h3>填写信息</h3>
|
||||
<div class="info-items">
|
||||
<p class="info-item">
|
||||
<span>姓名</span>
|
||||
<input type="text" class="info-item__name" placeholder="请填写姓名" />
|
||||
</p>
|
||||
<p class="info-item info-item__tel">
|
||||
<span>手机</span>
|
||||
<input type="number" class="info-item__tel" placeholder="请填写手机号" />
|
||||
</p>
|
||||
</div>
|
||||
<h3>个人介绍</h3>
|
||||
<div class="info-items">
|
||||
<p class="info-item f-p-0">
|
||||
<textarea class="info-item__intro" placeholder="请填写一段简要的自我介绍"></textarea>
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-confirm">
|
||||
<a href="javascript:;" class="info-confirm__btn">确认</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer>375 * 75</footer>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
222
src/styles/vw-rem/vw-rem.scss
Normal file
222
src/styles/vw-rem/vw-rem.scss
Normal file
@ -0,0 +1,222 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@import 'util';
|
||||
@import 'border';
|
||||
|
||||
.f-p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.f-border {
|
||||
@include border($direction: all, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
.f-border-bottom {
|
||||
@include border($direction: bottom, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
/* 圆角边框自定义多个角,顺序 */
|
||||
.f-border-radius {
|
||||
@include border(
|
||||
$radius: (
|
||||
10px,
|
||||
20px,
|
||||
30px,
|
||||
40px,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
@include root-font-size();
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: px2rem(28);
|
||||
background-color: #f8f8f8;
|
||||
|
||||
/* rem2px的使用方式,仅用于临时计算 */
|
||||
border-width: rem2px(0.6);
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
header {
|
||||
height: px2rem(300);
|
||||
line-height: px2rem(300);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
/* 容器宽高比 */
|
||||
// .header {
|
||||
// @include aspect-ratio(
|
||||
// // $width: px2rem(600),
|
||||
// // $sub: ".header-content",
|
||||
// $aspectX: 375,
|
||||
// $aspectY: 150
|
||||
// )
|
||||
// }
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: px2rem(200);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: px2rem(120);
|
||||
height: px2rem(120);
|
||||
margin-bottom: px2rem(20);
|
||||
line-height: px2rem(120);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: px2rem(20);
|
||||
|
||||
h3 {
|
||||
position: relative;
|
||||
margin-top: px2rem(50);
|
||||
margin-left: px2rem(26);
|
||||
font-size: px2rem(30);
|
||||
|
||||
/* 字体也可以选择不使用rem
|
||||
@include font-size(30px);
|
||||
*/
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: px2rem(-20);
|
||||
width: px2rem(12);
|
||||
height: 100%;
|
||||
background-color: #fc8200;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-items {
|
||||
margin-top: px2rem(20);
|
||||
margin-bottom: px2rem(20);
|
||||
}
|
||||
|
||||
.info-item {
|
||||
// border: 1px solid #ddd;
|
||||
|
||||
display: flex;
|
||||
padding: px2rem(30);
|
||||
padding-left: 0;
|
||||
margin-top: px2rem(20);
|
||||
|
||||
/* 多个边框调用 */
|
||||
&:not(.info-item__tel) {
|
||||
@include border($direction: all, $size: 1px, $color: #ddd, $style: solid, $radius: 50px);
|
||||
}
|
||||
|
||||
&.info-item__tel {
|
||||
@include border($direction: bottom, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
&:only-of-type {
|
||||
@include border($direction: all, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
/* 多个边框的动态更新 */
|
||||
&.hover {
|
||||
@include border(
|
||||
$direction: (
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
left,
|
||||
),
|
||||
$size: (
|
||||
3px,
|
||||
2px,
|
||||
1px,
|
||||
),
|
||||
$color: (
|
||||
#0f0,
|
||||
#ddd,
|
||||
),
|
||||
$style: dotted
|
||||
);
|
||||
}
|
||||
|
||||
span {
|
||||
/* 单个边框调用 */
|
||||
@include border($direction: right);
|
||||
|
||||
min-width: px2rem(120);
|
||||
text-align: center;
|
||||
|
||||
/* 单个边框的动态更新 */
|
||||
&.hover {
|
||||
@include border($direction: right, $size: 5px, $color: #0f0);
|
||||
}
|
||||
|
||||
// border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
font-size: px2rem(28);
|
||||
border: none;
|
||||
outline: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: px2rem(250);
|
||||
padding: px2rem(20);
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: px2rem(28);
|
||||
-webkit-text-size-adjust: none;
|
||||
text-size-adjust: none;
|
||||
border: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
}
|
||||
|
||||
.info-confirm {
|
||||
margin-bottom: px2rem(40);
|
||||
text-align: center;
|
||||
|
||||
&__btn {
|
||||
display: inline-block;
|
||||
width: px2rem(200);
|
||||
height: px2rem(80);
|
||||
margin-top: px2rem(80);
|
||||
line-height: px2rem(80);
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
background-color: #fc8200;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
height: px2rem(150);
|
||||
line-height: px2rem(150);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
513
src/styles/vw/css/vw.css
Normal file
513
src/styles/vw/css/vw.css
Normal file
@ -0,0 +1,513 @@
|
||||
.f-p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.f-border::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.f-border::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.f-border::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-bottom {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-bottom {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.f-border-bottom::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
pointer-events: none;
|
||||
background-color: #ddd;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-bottom::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.f-border-bottom::after {
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.f-border-bottom::after {
|
||||
-webkit-transform: scaleY(0.3333333333);
|
||||
transform: scaleY(0.3333333333);
|
||||
}
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-radius {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.f-border-radius {
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.f-border-radius::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.f-border-radius::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 50%;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.f-border-radius::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 50%;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 3.7333333333vw;
|
||||
background-color: #f8f8f8;
|
||||
border-width: 120px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 40vw;
|
||||
line-height: 40vw;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 40%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header > * {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 26.6666666667vw;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav ul .icon {
|
||||
width: 16vw;
|
||||
height: 16vw;
|
||||
margin-bottom: 2.6666666667vw;
|
||||
line-height: 16vw;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 2.6666666667vw;
|
||||
}
|
||||
|
||||
main h3 {
|
||||
position: relative;
|
||||
margin-top: 6.6666666667vw;
|
||||
margin-left: 3.4666666667vw;
|
||||
font-size: 4vw;
|
||||
}
|
||||
|
||||
main h3::before {
|
||||
position: absolute;
|
||||
left: -2.6666666667vw;
|
||||
width: 1.6vw;
|
||||
height: 100%;
|
||||
background-color: #fc8200;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.info-items {
|
||||
margin-top: 2.6666666667vw;
|
||||
margin-bottom: 2.6666666667vw;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
padding: 4vw;
|
||||
padding-left: 0;
|
||||
margin-top: 2.6666666667vw;
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:not(.info-item__tel) {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 50px;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:not(.info-item__tel) {
|
||||
position: relative;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
||||
.info-item:not(.info-item__tel)::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item:not(.info-item__tel)::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 100px;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item:not(.info-item__tel)::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 150px;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item.info-item__tel::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
pointer-events: none;
|
||||
background-color: #ddd;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item.info-item__tel::after {
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item.info-item__tel::after {
|
||||
-webkit-transform: scaleY(0.3333333333);
|
||||
transform: scaleY(0.3333333333);
|
||||
}
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:only-of-type {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item:only-of-type {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.info-item:only-of-type::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border: 1px solid #ddd;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item:only-of-type::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item:only-of-type::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.hover {
|
||||
border-top: 3px dotted #0f0;
|
||||
border-right: 2px dotted #ddd;
|
||||
border-bottom: 1px dotted #0f0;
|
||||
border-left: 3px dotted #0f0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item.hover {
|
||||
position: relative;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.info-item.hover::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
border-top: 3px solid #0f0;
|
||||
border-right: 2px solid #ddd;
|
||||
border-bottom: 1px solid #0f0;
|
||||
border-left: 3px solid #0f0;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item.hover::after {
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item.hover::after {
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
border-radius: 0;
|
||||
-webkit-transform: scale(0.3333333333, 0.3333333333);
|
||||
transform: scale(0.3333333333, 0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
min-width: 16vw;
|
||||
text-align: center;
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item span::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background-color: #ddd;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item span::after {
|
||||
-webkit-transform: scaleX(0.5);
|
||||
transform: scaleX(0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item span::after {
|
||||
-webkit-transform: scaleX(0.3333333333);
|
||||
transform: scaleX(0.3333333333);
|
||||
}
|
||||
}
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span.hover {
|
||||
border-right: 5px solid #0f0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span.hover {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-item span.hover::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
background-color: #0f0;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.info-item span.hover::after {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2) {
|
||||
.info-item span.hover::after {
|
||||
-webkit-transform: scaleX(0.5);
|
||||
transform: scaleX(0.5);
|
||||
}
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 3) {
|
||||
.info-item span.hover::after {
|
||||
-webkit-transform: scaleX(0.3333333333);
|
||||
transform: scaleX(0.3333333333);
|
||||
}
|
||||
}
|
||||
|
||||
.info-item input {
|
||||
width: 100%;
|
||||
font-size: 3.7333333333vw;
|
||||
border: none;
|
||||
outline: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
.info-item textarea {
|
||||
width: 100%;
|
||||
height: 33.3333333333vw;
|
||||
padding: 2.6666666667vw;
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 3.7333333333vw;
|
||||
-webkit-text-size-adjust: none;
|
||||
text-size-adjust: none;
|
||||
border: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
.info-confirm {
|
||||
margin-bottom: 5.3333333333vw;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-confirm__btn {
|
||||
display: inline-block;
|
||||
width: 26.6666666667vw;
|
||||
height: 10.6666666667vw;
|
||||
margin-top: 10.6666666667vw;
|
||||
line-height: 10.6666666667vw;
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
background-color: #fc8200;
|
||||
}
|
||||
|
||||
footer {
|
||||
height: 20vw;
|
||||
line-height: 20vw;
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
7
src/styles/vw/css/vw.css.map
Normal file
7
src/styles/vw/css/vw.css.map
Normal file
File diff suppressed because one or more lines are too long
58
src/styles/vw/index.html
Normal file
58
src/styles/vw/index.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>VW布局</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta lang="zh-CN" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
|
||||
<link rel="stylesheet" href="./css/vw.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<section class="container">
|
||||
<!-- 此处为固定宽高比的例子 -->
|
||||
<header class="header">
|
||||
<div class="header-content">固定纵横比 375 * 150</div>
|
||||
</header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">60 * 60</span>
|
||||
<span>导航入口</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon f-border-radius">圆角</span>
|
||||
<span class="f-border">导航入口</span>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<main>
|
||||
<h3>填写信息</h3>
|
||||
<div class="info-items">
|
||||
<p class="info-item">
|
||||
<span>姓名</span>
|
||||
<input type="text" class="info-item__name" placeholder="请填写姓名" />
|
||||
</p>
|
||||
<p class="info-item info-item__tel">
|
||||
<span>手机</span>
|
||||
<input type="number" class="info-item__tel" placeholder="请填写手机号" />
|
||||
</p>
|
||||
</div>
|
||||
<h3>个人介绍</h3>
|
||||
<div class="info-items">
|
||||
<p class="info-item f-p-0">
|
||||
<textarea class="info-item__intro" placeholder="请填写一段简要的自我介绍"></textarea>
|
||||
</p>
|
||||
</div>
|
||||
<div class="info-confirm">
|
||||
<a href="javascript:;" class="info-confirm__btn">确认</a>
|
||||
</div>
|
||||
</main>
|
||||
<footer>375 * 75</footer>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
230
src/styles/vw/scss/_border.scss
Normal file
230
src/styles/vw/scss/_border.scss
Normal file
@ -0,0 +1,230 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/**
|
||||
* 获取边框某项对应的值
|
||||
* @example getBorderItemValue(10px, 2)
|
||||
* @param {string|list} $item 某一项或多个项的列表
|
||||
* @param {number} $index 下标
|
||||
* @return {string} 项值
|
||||
*/
|
||||
@function getBorderItemValue($item, $index) {
|
||||
@if (type-of($item) == list) {
|
||||
@if ($index > length($item)) {
|
||||
$index: 1;
|
||||
}
|
||||
|
||||
@return nth($item, $index);
|
||||
} @else {
|
||||
@return $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为百分比
|
||||
* @param {number} $value 值
|
||||
* @return {boolean} 是否为百分比
|
||||
*/
|
||||
@function is-percentage($value) {
|
||||
@return type-of($value) == number and unit($value) == '%';
|
||||
}
|
||||
|
||||
/**
|
||||
* 边框圆角,支持单个值与多个值,在高清设备下px圆角加倍
|
||||
* @param {number|list} $radius 圆角值
|
||||
* @param {number} $ratio 设备像素比
|
||||
*/
|
||||
@mixin border-radius($radius: 0, $ratio: 1) {
|
||||
$border-radius-corner: (top-left, top-right, bottom-right, bottom-left);
|
||||
|
||||
/* 列表 按照四个角的顺序匹配 */
|
||||
@if (type-of($radius) == list) {
|
||||
@for $i from 1 through length($radius) {
|
||||
$item: nth($radius, $i);
|
||||
$corner: nth($border-radius-corner, $i);
|
||||
|
||||
/* 普通设备,或者为百分比则直接使用圆角值 */
|
||||
@if $ratio == 1 or is-percentage($item) {
|
||||
border-#{$corner}-radius: $item;
|
||||
}
|
||||
|
||||
/* 否则翻$ratio倍 */
|
||||
@else {
|
||||
border-#{$corner}-radius: $item * $ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 单个值 */
|
||||
@else {
|
||||
@if $ratio == 1 or is-percentage($radius) {
|
||||
border-radius: $radius;
|
||||
} @else {
|
||||
border-radius: $radius * $ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 元素边框
|
||||
* @param {string|list} $direction: all 为all或列表时表示多个方向的边框,否则为单个边框
|
||||
* @param {string|list} $size: 1px 边框尺寸,为列表时表将按照direction的顺序取值
|
||||
* @param {string|list} $style: solid 边框样式,高清设备下仅支持solid,同上
|
||||
* @param {string|list} $color: #ddd 边框颜色,同上
|
||||
* @param {string} $position: relative 元素定位方式,一般为relative即可
|
||||
* @param {string} $radius: 0 边框圆角
|
||||
*/
|
||||
@mixin border(
|
||||
$direction: all,
|
||||
$size: 1px,
|
||||
$style: solid,
|
||||
$color: #ddd,
|
||||
$position: relative,
|
||||
$radius: 0
|
||||
) {
|
||||
/* 多个边框 */
|
||||
@if $direction == all or type-of($direction) == list {
|
||||
/* 普通设备 */
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
@include border-radius($radius);
|
||||
|
||||
@if $direction == all {
|
||||
border: $size $style $color;
|
||||
} @else {
|
||||
@for $i from 1 through length($direction) {
|
||||
$item: nth($direction, $i);
|
||||
|
||||
border-#{$item}: getborderitemvalue($size, $i)
|
||||
getborderitemvalue($style, $i)
|
||||
getborderitemvalue($color, $i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 高清设备 */
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
@include border-multiple(
|
||||
$direction: $direction,
|
||||
$size: $size,
|
||||
$color: $color,
|
||||
$position: $position,
|
||||
$radius: $radius
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* 单个边框 */
|
||||
@else {
|
||||
/* 普通设备 */
|
||||
@media not screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
border-#{$direction}: $size $style $color;
|
||||
}
|
||||
|
||||
/* 高清设备 */
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
@include border-single(
|
||||
$direction: $direction,
|
||||
$size: $size,
|
||||
$color: $color,
|
||||
$position: $position
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 实现1物理像素的单条边框线 */
|
||||
@mixin border-single($direction: bottom, $size: 1px, $color: #ddd, $position: relative) {
|
||||
position: $position;
|
||||
|
||||
&::after {
|
||||
/* 上下 */
|
||||
@if ($direction == top or $direction == bottom) {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: $size;
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 2) {
|
||||
-webkit-transform: scaleY(0.5);
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 3) {
|
||||
-webkit-transform: scaleY(0.333333333333);
|
||||
transform: scaleY(0.333333333333);
|
||||
}
|
||||
}
|
||||
|
||||
/* 左右 */
|
||||
@else if ($direction == left or $direction == right) {
|
||||
top: 0;
|
||||
width: $size;
|
||||
height: 100%;
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 2) {
|
||||
-webkit-transform: scaleX(0.5);
|
||||
transform: scaleX(0.5);
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 3) {
|
||||
-webkit-transform: scaleX(0.333333333333);
|
||||
transform: scaleX(0.333333333333);
|
||||
}
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
background-color: $color;
|
||||
content: '';
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
-webkit-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
#{$direction}: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 实现1物理像素的多条边框线 */
|
||||
@mixin border-multiple($direction: all, $size: 1px, $color: #ddd, $position: relative, $radius: 0) {
|
||||
@include border-radius($radius);
|
||||
|
||||
position: $position;
|
||||
|
||||
&::after {
|
||||
@if $direction == all {
|
||||
border: $size solid $color;
|
||||
} @else {
|
||||
@for $i from 1 through length($direction) {
|
||||
$item: nth($direction, $i);
|
||||
|
||||
border-#{$item}: getborderitemvalue($size, $i) solid getborderitemvalue($color, $i);
|
||||
}
|
||||
}
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
-webkit-transform-origin: top left;
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 2) {
|
||||
@include border-radius($radius, 2);
|
||||
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
-webkit-transform: scale(0.5, 0.5);
|
||||
transform: scale(0.5, 0.5);
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-device-pixel-ratio: 3) {
|
||||
@include border-radius($radius, 3);
|
||||
|
||||
width: 300%;
|
||||
height: 300%;
|
||||
-webkit-transform: scale(0.333333333333, 0.333333333333);
|
||||
transform: scale(0.333333333333, 0.333333333333);
|
||||
}
|
||||
}
|
||||
}
|
||||
66
src/styles/vw/scss/_util.scss
Normal file
66
src/styles/vw/scss/_util.scss
Normal file
@ -0,0 +1,66 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
/* 移动端页面设计稿宽度 */
|
||||
$design-width: 750;
|
||||
|
||||
/* 移动端页面设计稿dpr基准值 */
|
||||
$design-dpr: 2;
|
||||
|
||||
/*
|
||||
vw与px对应关系,100vw为视窗宽度,$vw即为$px对应占多宽
|
||||
|
||||
$px $vw
|
||||
------------- === ------------
|
||||
$design-width 100vw
|
||||
*/
|
||||
|
||||
/* 单位px转化为vw */
|
||||
@function px2vw($px) {
|
||||
@return ($px / $design-width) * 100vw;
|
||||
}
|
||||
|
||||
/* 单位vw转化为px,可用于根据vw单位快速计算原px */
|
||||
@function vw2px($vw) {
|
||||
@return #{($vw / 100) * $design-width}px;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实现固定宽高比
|
||||
* @param {string} $position: relative 定位方式
|
||||
* @param {string} $width: 100% 容器宽度
|
||||
* @param {string} $sub: null 容器的目标子元素
|
||||
* @param {number} $aspectX: 1 容器宽
|
||||
* @param {number} $aspectY: 1 容器高
|
||||
*/
|
||||
@mixin aspect-ratio($position: relative, $width: 100%, $sub: null, $aspectX: 1, $aspectY: 1) {
|
||||
@if $sub == null {
|
||||
$sub: '*';
|
||||
}
|
||||
|
||||
position: $position;
|
||||
width: $width;
|
||||
height: 0;
|
||||
padding-top: percentage($aspectY / $aspectX);
|
||||
overflow: hidden;
|
||||
|
||||
& > #{$sub} {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 设置字体大小,不使用rem单位, 根据dpr值分段调整 */
|
||||
@mixin font-size($fontSize) {
|
||||
font-size: $fontSize / $design-dpr;
|
||||
|
||||
[data-dpr='2'] & {
|
||||
font-size: $fontSize / $design-dpr * 2;
|
||||
}
|
||||
|
||||
[data-dpr='3'] & {
|
||||
font-size: $fontSize / $design-dpr * 3;
|
||||
}
|
||||
}
|
||||
211
src/styles/vw/scss/vw.scss
Normal file
211
src/styles/vw/scss/vw.scss
Normal file
@ -0,0 +1,211 @@
|
||||
@charset "UTF-8";
|
||||
|
||||
@import './util';
|
||||
@import './border';
|
||||
|
||||
.f-p-0 {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.f-border {
|
||||
@include border($direction: all, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
.f-border-bottom {
|
||||
@include border($direction: bottom, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
/* 圆角边框百分比 */
|
||||
.f-border-radius {
|
||||
@include border($direction: all, $radius: 50%);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: px2vw(28);
|
||||
background-color: #f8f8f8;
|
||||
|
||||
/* vw2px的使用方式,仅用于临时计算 */
|
||||
border-width: vw2px(16);
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
header {
|
||||
height: px2vw(300);
|
||||
line-height: px2vw(300);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
/* 容器宽高比 */
|
||||
.header {
|
||||
@include aspect-ratio(
|
||||
// $width: px2vw(600),
|
||||
// $sub: ".header-content",
|
||||
$aspectX: 375,
|
||||
$aspectY: 150
|
||||
);
|
||||
}
|
||||
|
||||
nav ul {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: px2vw(200);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: px2vw(120);
|
||||
height: px2vw(120);
|
||||
margin-bottom: px2vw(20);
|
||||
line-height: px2vw(120);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
padding: px2vw(20);
|
||||
|
||||
h3 {
|
||||
position: relative;
|
||||
margin-top: px2vw(50);
|
||||
margin-left: px2vw(26);
|
||||
font-size: px2vw(30);
|
||||
|
||||
/* 字体也可以选择不使用rem
|
||||
@include font-size(30px);
|
||||
*/
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: px2vw(-20);
|
||||
width: px2vw(12);
|
||||
height: 100%;
|
||||
background-color: #fc8200;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info-items {
|
||||
margin-top: px2vw(20);
|
||||
margin-bottom: px2vw(20);
|
||||
}
|
||||
|
||||
.info-item {
|
||||
// border: 1px solid #ddd;
|
||||
|
||||
display: flex;
|
||||
padding: px2vw(30);
|
||||
padding-left: 0;
|
||||
margin-top: px2vw(20);
|
||||
|
||||
/* 多个边框调用 */
|
||||
&:not(.info-item__tel) {
|
||||
@include border($direction: all, $size: 1px, $color: #ddd, $style: solid, $radius: 50px);
|
||||
}
|
||||
|
||||
&.info-item__tel {
|
||||
@include border($direction: bottom, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
&:only-of-type {
|
||||
@include border($direction: all, $size: 1px, $color: #ddd, $style: solid);
|
||||
}
|
||||
|
||||
/* 多个边框的动态更新 */
|
||||
&.hover {
|
||||
@include border(
|
||||
$direction: (
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
left,
|
||||
),
|
||||
$size: (
|
||||
3px,
|
||||
2px,
|
||||
1px,
|
||||
),
|
||||
$color: (
|
||||
#0f0,
|
||||
#ddd,
|
||||
),
|
||||
$style: dotted
|
||||
);
|
||||
}
|
||||
|
||||
span {
|
||||
/* 单个边框调用 */
|
||||
@include border($direction: right);
|
||||
|
||||
min-width: px2vw(120);
|
||||
text-align: center;
|
||||
|
||||
/* 单个边框的动态更新 */
|
||||
&.hover {
|
||||
@include border($direction: right, $size: 5px, $color: #0f0);
|
||||
}
|
||||
|
||||
// border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
font-size: px2vw(28);
|
||||
border: none;
|
||||
outline: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: px2vw(250);
|
||||
padding: px2vw(20);
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: px2vw(28);
|
||||
-webkit-text-size-adjust: none;
|
||||
text-size-adjust: none;
|
||||
border: none;
|
||||
caret-color: #fc8200;
|
||||
}
|
||||
}
|
||||
|
||||
.info-confirm {
|
||||
margin-bottom: px2vw(40);
|
||||
text-align: center;
|
||||
|
||||
&__btn {
|
||||
display: inline-block;
|
||||
width: px2vw(200);
|
||||
height: px2vw(80);
|
||||
margin-top: px2vw(80);
|
||||
line-height: px2vw(80);
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
text-decoration: none !important;
|
||||
background-color: #fc8200;
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
height: px2vw(150);
|
||||
line-height: px2vw(150);
|
||||
text-align: center;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
128
src/utils/Storage.ts
Normal file
128
src/utils/Storage.ts
Normal file
@ -0,0 +1,128 @@
|
||||
// 默认缓存期限为7天
|
||||
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7;
|
||||
|
||||
/**
|
||||
* 创建本地缓存对象
|
||||
* @param {string=} prefixKey -
|
||||
* @param {Object} [storage=localStorage] - sessionStorage | localStorage
|
||||
*/
|
||||
export const createStorage = ({ prefixKey = '', storage = localStorage } = {}) => {
|
||||
/**
|
||||
* 本地缓存类
|
||||
* @class Storage
|
||||
*/
|
||||
const Storage = class {
|
||||
private storage = storage;
|
||||
private prefixKey?: string = prefixKey;
|
||||
|
||||
private getKey(key: string) {
|
||||
return `${this.prefixKey}${key}`.toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 设置缓存
|
||||
* @param {string} key 缓存键
|
||||
* @param {*} value 缓存值
|
||||
* @param expire
|
||||
*/
|
||||
set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||
const stringData = JSON.stringify({
|
||||
value,
|
||||
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
|
||||
});
|
||||
this.storage.setItem(this.getKey(key), stringData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @param {string} key 缓存键
|
||||
* @param {*=} def 默认值
|
||||
*/
|
||||
get<T = any>(key: string, def: any = null): T {
|
||||
const item = this.storage.getItem(this.getKey(key));
|
||||
if (item) {
|
||||
try {
|
||||
const data = JSON.parse(item);
|
||||
const { value, expire } = data;
|
||||
// 在有效期内直接返回
|
||||
if (expire === null || expire >= Date.now()) {
|
||||
return value;
|
||||
}
|
||||
this.remove(this.getKey(key));
|
||||
} catch (e) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存删除某项
|
||||
* @param {string} key
|
||||
*/
|
||||
remove(key: string) {
|
||||
console.log(key, '搜索');
|
||||
this.storage.removeItem(this.getKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有缓存
|
||||
* @memberOf Cache
|
||||
*/
|
||||
clear(): void {
|
||||
this.storage.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置cookie
|
||||
* @param {string} name cookie 名称
|
||||
* @param {*} value cookie 值
|
||||
* @param {number=} expire 过期时间
|
||||
* 如果过期时间为设置,默认关闭浏览器自动删除
|
||||
* @example
|
||||
*/
|
||||
setCookie(name: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) {
|
||||
document.cookie = `${this.getKey(name)}=${value}; Max-Age=${expire}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名字获取cookie值
|
||||
* @param name
|
||||
*/
|
||||
getCookie(name: string): string {
|
||||
const cookieArr = document.cookie.split('; ');
|
||||
for (let i = 0, length = cookieArr.length; i < length; i++) {
|
||||
const kv = cookieArr[i].split('=');
|
||||
if (kv[0] === this.getKey(name)) {
|
||||
return kv[1];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据名字删除指定的cookie
|
||||
* @param {string} key
|
||||
*/
|
||||
removeCookie(key: string) {
|
||||
this.setCookie(key, 1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空cookie,使所有cookie失效
|
||||
*/
|
||||
clearCookie(): void {
|
||||
const keys = document.cookie.match(/[^ =;]+(?==)/g);
|
||||
if (keys) {
|
||||
for (let i = keys.length; i--; ) {
|
||||
document.cookie = `${keys[i]}=0;expire=${new Date(0).toUTCString()}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return new Storage();
|
||||
};
|
||||
|
||||
export const Storage = createStorage();
|
||||
|
||||
export default Storage;
|
||||
32
src/utils/httpEnum.ts
Normal file
32
src/utils/httpEnum.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @description: 请求结果集
|
||||
*/
|
||||
export enum ResultEnum {
|
||||
SUCCESS = 0,
|
||||
ERROR = 7,
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 请求方法
|
||||
*/
|
||||
export enum RequestEnum {
|
||||
GET = 'GET',
|
||||
POST = 'POST',
|
||||
PATCH = 'PATCH',
|
||||
PUT = 'PUT',
|
||||
DELETE = 'DELETE',
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 常用的contentTyp类型
|
||||
*/
|
||||
export enum ContentTypeEnum {
|
||||
// json
|
||||
JSON = 'application/json;charset=UTF-8',
|
||||
// json
|
||||
TEXT = 'text/plain;charset=UTF-8',
|
||||
// form-data 一般配合qs
|
||||
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||
// form-data 上传
|
||||
FORM_DATA = 'multipart/form-data;charset=UTF-8',
|
||||
}
|
||||
13
src/utils/importAll.ts
Normal file
13
src/utils/importAll.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @description 按照一定路径规则批量导入文件
|
||||
* @param pathRule eg: pathRule = './modules/*.ts'
|
||||
*/
|
||||
export const importAll = (pathRule: string) => {
|
||||
const allModules = import.meta.globEager(pathRule);
|
||||
const modules = {} as any;
|
||||
Object.keys(allModules).forEach((path) => {
|
||||
const fileName = path.replace(/(.*\/)*([^.]+).*/gi, '$2');
|
||||
modules[fileName] = allModules[path].default;
|
||||
});
|
||||
return modules;
|
||||
};
|
||||
12
src/utils/index.ts
Normal file
12
src/utils/index.ts
Normal file
@ -0,0 +1,12 @@
|
||||
//秒转化成 时分秒
|
||||
export function second(second: number) {
|
||||
second = second || 0;
|
||||
if (second === 0 || second === Infinity || second.toString() === 'NaN') {
|
||||
return '00:00';
|
||||
}
|
||||
const add0 = (num: number) => (num < 10 ? `0${num}` : `${num}`);
|
||||
const hour = Math.floor(second / 3600);
|
||||
const min = Math.floor((second - hour * 3600) / 60);
|
||||
const sec = Math.floor(second - hour * 3600 - min * 60);
|
||||
return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':');
|
||||
}
|
||||
139
src/utils/request.ts
Normal file
139
src/utils/request.ts
Normal file
@ -0,0 +1,139 @@
|
||||
import { ref } from 'vue';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import qs from 'qs';
|
||||
import { showToast, showLoadingToast, closeToast } from 'vant';
|
||||
import { ContentTypeEnum } from './httpEnum';
|
||||
import { backFillLoginData } from '@/plugins/public';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getLogin } from '@/api/demo';
|
||||
|
||||
// 超文本传输协议
|
||||
let href = ref('http:');
|
||||
if (location.href.includes('https:')) {
|
||||
href.value = 'https:';
|
||||
}
|
||||
|
||||
// 创建一个axios实例
|
||||
const service = axios.create({
|
||||
baseURL: `${href.value}${import.meta.env.VITE_BASE_API as string}`,
|
||||
withCredentials: false, // 当跨域请求时发送cookie
|
||||
timeout: 20000, // 请求超时时间
|
||||
});
|
||||
|
||||
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
|
||||
hideLoading?: boolean;
|
||||
}
|
||||
|
||||
interface BaseResponse<T = any> {
|
||||
code: number;
|
||||
data: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
// request请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: CustomAxiosRequestConfig) => {
|
||||
// 不传递默认开启loading
|
||||
if (!config.hideLoading) {
|
||||
showLoadingToast({
|
||||
message: '加载中...',
|
||||
forbidClick: true,
|
||||
});
|
||||
}
|
||||
const userStore = useUserStore();
|
||||
if ((localStorage.getItem('rt_token') || userStore.token) && config.headers) {
|
||||
config.headers['Authorization'] = `Bearer ${localStorage.getItem('rt_token') || userStore.token}`;
|
||||
}
|
||||
if (config.headers) {
|
||||
config.headers['Version'] = `${import.meta.env.VITE_BASE_API_VERSION}`;
|
||||
}
|
||||
let parameter = `open_id=${localStorage.getItem('rt_openid') || ''}&from_user_id=${localStorage.getItem('rt_from_user_id') || ''}&from_open_id=${localStorage.getItem('rt_from_open_id') || ''}&invite_user_id=${localStorage.getItem('rt_invite_user_id') || ''}&from_source=oa&from_type=${localStorage.getItem('rt_from_type') || ''}`;
|
||||
if (config.url?.includes('?')) {
|
||||
config.url = `${config.url}&${parameter}`;
|
||||
} else {
|
||||
config.url = `${config.url}?${parameter}`;
|
||||
}
|
||||
const contentType = config.headers?.['content-type'] || config.headers?.['Content-Type'];
|
||||
const data = config.data;
|
||||
if (config.method?.toLocaleUpperCase() == 'POST' && data) {
|
||||
if (ContentTypeEnum.FORM_DATA == contentType) {
|
||||
const fd = new FormData();
|
||||
Object.keys(data).forEach((key) => fd.append(key, data[key]));
|
||||
config.data = fd;
|
||||
} else if (ContentTypeEnum.FORM_URLENCODED == contentType) {
|
||||
config.data = qs.stringify(config.data);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
console.log(error, '*--------*');
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
// response相应拦截器
|
||||
const error = ref(1);
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const userStore = useUserStore();
|
||||
const res = response.data;
|
||||
if (res.code === 1) {
|
||||
closeToast();
|
||||
// 服务器访问出错了~
|
||||
showToast(res.message);
|
||||
return Promise.reject(res.message || 'code: 1');
|
||||
} else if (res.code === 2) {
|
||||
// 登录超时,重新登录
|
||||
closeToast();
|
||||
error.value += 1;
|
||||
if (error.value <= 2) {
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
} else {
|
||||
localStorage.removeItem('rt_token');
|
||||
getLogin().then((res) => {
|
||||
let result = res.data;
|
||||
backFillLoginData(result, userStore);
|
||||
setTimeout(() => {
|
||||
window.location.replace(location.href);
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(res.message);
|
||||
} else if (res.code === 3) {
|
||||
closeToast();
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
} else {
|
||||
window.location.replace(`https://health.ufutx.com/go/api/h5/v1/wechat/auth?forwardurl=${encodeURIComponent(location.href)}`);
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
} else {
|
||||
closeToast();
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
},
|
||||
(error: Error) => {
|
||||
if (error.message?.includes('timeout')) {
|
||||
showToast('网络异常,请稍后重试!');
|
||||
}
|
||||
console.log(`err${error}`);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
const request = <T = any>(config: CustomAxiosRequestConfig): Promise<BaseResponse<T>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
service
|
||||
.request<BaseResponse<T>>(config)
|
||||
.then((res) => resolve(res.data))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export default request;
|
||||
141
src/utils/requestApp.ts
Normal file
141
src/utils/requestApp.ts
Normal file
@ -0,0 +1,141 @@
|
||||
import { ref } from 'vue';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import qs from 'qs';
|
||||
import { showToast, showLoadingToast, closeToast } from 'vant';
|
||||
import { ContentTypeEnum } from './httpEnum';
|
||||
import { backFillLoginData, CutOutQuery } from '@/plugins/public';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getLogin } from '@/api/demo';
|
||||
|
||||
// 超文本传输协议
|
||||
let href = ref('http:');
|
||||
if (location.href.includes('https:')) {
|
||||
href.value = 'https:';
|
||||
}
|
||||
|
||||
// 创建一个axios实例
|
||||
const service = axios.create({
|
||||
baseURL: `${href.value}${import.meta.env.VITE_BASE_API_go as string}`,
|
||||
withCredentials: false, // 当跨域请求时发送cookie
|
||||
timeout: 20000, // 请求超时时间
|
||||
});
|
||||
|
||||
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
|
||||
hideLoading?: boolean;
|
||||
}
|
||||
|
||||
interface BaseResponse<T = any> {
|
||||
code: number;
|
||||
data: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
// request请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: CustomAxiosRequestConfig) => {
|
||||
// 不传递默认开启loading
|
||||
if (!config.hideLoading) {
|
||||
showLoadingToast({
|
||||
message: '加载中...',
|
||||
forbidClick: true,
|
||||
});
|
||||
}
|
||||
// const userStore = useUserStore();
|
||||
if ((localStorage.getItem('app_token') || import.meta.env.MODE === 'development') && config.headers) {
|
||||
config.headers['Authorization'] = `Bearer ${localStorage.getItem('app_token') || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJDcmVhdGVkQXQiOjE3MjMxOTA0MDIsIkV4cGlyZWRBdCI6MTcyNTc4MjQwMiwiVmVyc2lvbiI6MTAwLCJVc2VyaWQiOjIzNSwiZXhwIjoyNTg3MTkwNDAyfQ.AloagIYDshky0jxn-aGUwWloU8GWbRAQR0cKURIZqNk'}`;
|
||||
}
|
||||
if (config.headers) {
|
||||
config.headers['Version'] = `${import.meta.env.VITE_BASE_API_VERSION}`;
|
||||
}
|
||||
let parameter = `from_user_id=${localStorage.getItem('rt_from_user_id') || ''}&invite_user_id=${localStorage.getItem('rt_invite_user_id') || ''}&referrer_user_id=${localStorage.getItem('rt_referrer_user_id') || ''}&from_source=rt&from_type=${localStorage.getItem('rt_from_type') || ''}`;
|
||||
if (config.url?.includes('?')) {
|
||||
config.url = `${config.url}&${parameter}`;
|
||||
} else {
|
||||
config.url = `${config.url}?${parameter}`;
|
||||
}
|
||||
const contentType = config.headers?.['content-type'] || config.headers?.['Content-Type'];
|
||||
const data = config.data;
|
||||
if (config.method?.toLocaleUpperCase() == 'POST' && data) {
|
||||
if (ContentTypeEnum.FORM_DATA == contentType) {
|
||||
const fd = new FormData();
|
||||
Object.keys(data).forEach((key) => fd.append(key, data[key]));
|
||||
config.data = fd;
|
||||
} else if (ContentTypeEnum.FORM_URLENCODED == contentType) {
|
||||
config.data = qs.stringify(config.data);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
console.log(error, '*--------*');
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
// response相应拦截器
|
||||
const error = ref(1);
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const userStore = useUserStore();
|
||||
const res = response.data;
|
||||
if (res.code === 1) {
|
||||
closeToast();
|
||||
// 服务器访问出错了~
|
||||
showToast(`${res.message}。`);
|
||||
return Promise.reject(res.message || 'code: 1');
|
||||
} else if (res.code === 2) {
|
||||
// 登录超时,重新登录
|
||||
closeToast();
|
||||
error.value += 1;
|
||||
if (error.value <= 2) {
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
} else {
|
||||
localStorage.removeItem('rt_token');
|
||||
getLogin().then((res) => {
|
||||
let result = res.data;
|
||||
backFillLoginData(result, userStore);
|
||||
setTimeout(() => {
|
||||
window.location.replace(location.href);
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(res.message);
|
||||
} else if (res.code === 3) {
|
||||
closeToast();
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
localStorage.setItem('rt_openid', 'oHGap6DNY15882HSxh00rtqxaTHU');
|
||||
} else {
|
||||
let url = `${CutOutQuery(location.href, 'url')}`;
|
||||
window.location.replace(`https://health.ufutx.com/go/api/h5/v1/wechat/auth?forwardurl=${encodeURIComponent(url)}`);
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
} else {
|
||||
closeToast();
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
},
|
||||
(error: Error) => {
|
||||
if (error.message?.includes('timeout')) {
|
||||
showToast('网络异常,请稍后重试!');
|
||||
}
|
||||
console.log(`err${error}`);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
const request = <T = any>(config: CustomAxiosRequestConfig): Promise<BaseResponse<T>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
service
|
||||
.request<BaseResponse<T>>(config)
|
||||
.then((res) => resolve(res.data))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export default request;
|
||||
141
src/utils/requestAppPHP.ts
Normal file
141
src/utils/requestAppPHP.ts
Normal file
@ -0,0 +1,141 @@
|
||||
import { ref } from 'vue';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import qs from 'qs';
|
||||
import { showToast, showLoadingToast, closeToast } from 'vant';
|
||||
import { ContentTypeEnum } from './httpEnum';
|
||||
import { backFillLoginData, CutOutQuery } from '@/plugins/public';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getLogin } from '@/api/demo';
|
||||
|
||||
// 超文本传输协议
|
||||
let href = ref('http:');
|
||||
if (location.href.includes('https:')) {
|
||||
href.value = 'https:';
|
||||
}
|
||||
|
||||
// 创建一个axios实例
|
||||
const service = axios.create({
|
||||
baseURL: `${href.value}${import.meta.env.VITE_BASE_API as string}`,
|
||||
withCredentials: false, // 当跨域请求时发送cookie
|
||||
timeout: 20000, // 请求超时时间
|
||||
});
|
||||
|
||||
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
|
||||
hideLoading?: boolean;
|
||||
}
|
||||
|
||||
interface BaseResponse<T = any> {
|
||||
code: number;
|
||||
data: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
// request请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: CustomAxiosRequestConfig) => {
|
||||
// 不传递默认开启loading
|
||||
if (!config.hideLoading) {
|
||||
showLoadingToast({
|
||||
message: '加载中...',
|
||||
forbidClick: true,
|
||||
});
|
||||
}
|
||||
// const userStore = useUserStore();
|
||||
if ((localStorage.getItem('app_token') || import.meta.env.MODE === 'development') && config.headers) {
|
||||
config.headers['Authorization'] = `Bearer ${localStorage.getItem('app_token') || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJDcmVhdGVkQXQiOjE3MjMxOTA0MDIsIkV4cGlyZWRBdCI6MTcyNTc4MjQwMiwiVmVyc2lvbiI6MTAwLCJVc2VyaWQiOjIzNSwiZXhwIjoyNTg3MTkwNDAyfQ.AloagIYDshky0jxn-aGUwWloU8GWbRAQR0cKURIZqNk'}`;
|
||||
}
|
||||
if (config.headers) {
|
||||
config.headers['Version'] = `${import.meta.env.VITE_BASE_API_VERSION}`;
|
||||
}
|
||||
let parameter = `from_user_id=${localStorage.getItem('rt_from_user_id') || ''}&invite_user_id=${localStorage.getItem('rt_invite_user_id') || ''}&referrer_user_id=${localStorage.getItem('rt_referrer_user_id') || ''}&from_source=rt&from_type=${localStorage.getItem('rt_from_type') || ''}`;
|
||||
if (config.url?.includes('?')) {
|
||||
config.url = `${config.url}&${parameter}`;
|
||||
} else {
|
||||
config.url = `${config.url}?${parameter}`;
|
||||
}
|
||||
const contentType = config.headers?.['content-type'] || config.headers?.['Content-Type'];
|
||||
const data = config.data;
|
||||
if (config.method?.toLocaleUpperCase() == 'POST' && data) {
|
||||
if (ContentTypeEnum.FORM_DATA == contentType) {
|
||||
const fd = new FormData();
|
||||
Object.keys(data).forEach((key) => fd.append(key, data[key]));
|
||||
config.data = fd;
|
||||
} else if (ContentTypeEnum.FORM_URLENCODED == contentType) {
|
||||
config.data = qs.stringify(config.data);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
console.log(error, '*--------*');
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
// response相应拦截器
|
||||
const error = ref(1);
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const userStore = useUserStore();
|
||||
const res = response.data;
|
||||
if (res.code === 1) {
|
||||
closeToast();
|
||||
// 服务器访问出错了~
|
||||
showToast(`${res.message}。`);
|
||||
return Promise.reject(res.message || 'code: 1');
|
||||
} else if (res.code === 2) {
|
||||
// 登录超时,重新登录
|
||||
closeToast();
|
||||
error.value += 1;
|
||||
if (error.value <= 2) {
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
} else {
|
||||
localStorage.removeItem('rt_token');
|
||||
getLogin().then((res) => {
|
||||
let result = res.data;
|
||||
backFillLoginData(result, userStore);
|
||||
setTimeout(() => {
|
||||
window.location.replace(location.href);
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(res.message);
|
||||
} else if (res.code === 3) {
|
||||
closeToast();
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
localStorage.setItem('rt_openid', 'oHGap6DNY15882HSxh00rtqxaTHU');
|
||||
} else {
|
||||
let url = `${CutOutQuery(location.href, 'url')}`;
|
||||
window.location.replace(`https://health.ufutx.com/go/api/h5/v1/wechat/auth?forwardurl=${encodeURIComponent(url)}`);
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
} else {
|
||||
closeToast();
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
},
|
||||
(error: Error) => {
|
||||
if (error.message?.includes('timeout')) {
|
||||
showToast('网络异常,请稍后重试!');
|
||||
}
|
||||
console.log(`err${error}`);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
const request = <T = any>(config: CustomAxiosRequestConfig): Promise<BaseResponse<T>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
service
|
||||
.request<BaseResponse<T>>(config)
|
||||
.then((res) => resolve(res.data))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export default request;
|
||||
152
src/utils/requestGo.ts
Normal file
152
src/utils/requestGo.ts
Normal file
@ -0,0 +1,152 @@
|
||||
import { ref } from 'vue';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import qs from 'qs';
|
||||
import { showToast, showLoadingToast, closeToast } from 'vant';
|
||||
import { ContentTypeEnum } from './httpEnum';
|
||||
import { backFillLoginData, CutOutQuery, examineRegister } from '@/plugins/public';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getLogin } from '@/api/demo';
|
||||
import router from '@/router';
|
||||
|
||||
// 超文本传输协议
|
||||
let href = ref('http:');
|
||||
if (location.href.includes('https:')) {
|
||||
href.value = 'https:';
|
||||
}
|
||||
|
||||
// 创建一个axios实例
|
||||
const service = axios.create({
|
||||
baseURL: `${import.meta.env.VITE_BASE_API_go as string}`,
|
||||
withCredentials: false, // 当跨域请求时发送cookie
|
||||
timeout: 20000, // 请求超时时间
|
||||
});
|
||||
|
||||
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
|
||||
hideLoading?: boolean;
|
||||
}
|
||||
|
||||
interface BaseResponse<T = any> {
|
||||
code: number;
|
||||
data: T;
|
||||
msg: string;
|
||||
}
|
||||
|
||||
// request请求拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: CustomAxiosRequestConfig) => {
|
||||
// 不传递默认开启loading
|
||||
if (!config.hideLoading) {
|
||||
showLoadingToast({
|
||||
message: '加载中...',
|
||||
forbidClick: true,
|
||||
});
|
||||
}
|
||||
const userStore = useUserStore();
|
||||
if ((localStorage.getItem('rt_token') || userStore.token) && config.headers) {
|
||||
config.headers['Authorization'] = `Bearer ${localStorage.getItem('rt_token') || userStore.token}`;
|
||||
}
|
||||
if (config.headers) {
|
||||
config.headers['Version'] = `${import.meta.env.VITE_BASE_API_VERSION}`;
|
||||
}
|
||||
let parameter = `open_id=${localStorage.getItem('rt_openid') || ''}&from_user_id=${localStorage.getItem('rt_from_user_id') || ''}&from_open_id=${localStorage.getItem('rt_from_open_id') || ''}&invite_user_id=${localStorage.getItem('rt_invite_user_id') || ''}&referrer_user_id=${localStorage.getItem('rt_referrer_user_id') || ''}&from_source=rt&from_type=${localStorage.getItem('rt_from_type') || ''}`;
|
||||
if (config.url?.includes('?')) {
|
||||
config.url = `${config.url}&${parameter}`;
|
||||
} else {
|
||||
config.url = `${config.url}?${parameter}`;
|
||||
}
|
||||
const contentType = config.headers?.['content-type'] || config.headers?.['Content-Type'];
|
||||
const data = config.data;
|
||||
if (config.method?.toLocaleUpperCase() == 'POST' && data) {
|
||||
if (ContentTypeEnum.FORM_DATA == contentType) {
|
||||
const fd = new FormData();
|
||||
Object.keys(data).forEach((key) => fd.append(key, data[key]));
|
||||
config.data = fd;
|
||||
} else if (ContentTypeEnum.FORM_URLENCODED == contentType) {
|
||||
config.data = qs.stringify(config.data);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
console.log(error, '*--------*');
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
// response相应拦截器
|
||||
const error = ref(1);
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
const userStore = useUserStore();
|
||||
const res = response.data;
|
||||
if (res.code === 1) {
|
||||
closeToast();
|
||||
// 服务器访问出错了~
|
||||
showToast(res.message);
|
||||
return Promise.reject(res.message || 'code: 1');
|
||||
} else if (res.code === 2) {
|
||||
// 登录超时,重新登录
|
||||
closeToast();
|
||||
error.value += 1;
|
||||
if (error.value <= 2) {
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
} else {
|
||||
localStorage.removeItem('rt_token');
|
||||
getLogin().then((res) => {
|
||||
let result = res.data;
|
||||
// if (!res.data.id) {
|
||||
// examineRegister(router.currentRoute.value);
|
||||
// return;
|
||||
// }
|
||||
backFillLoginData(result, userStore);
|
||||
setTimeout(() => {
|
||||
window.location.replace(location.href);
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
return Promise.reject(res.message);
|
||||
} else if (res.code === 3) {
|
||||
closeToast();
|
||||
// 本地环境
|
||||
if (import.meta.env.MODE === 'development') {
|
||||
userStore.token = '53|SPv38Y7yBN7AFglo82Cze3hU1qVqJPL8QUG4UDen';
|
||||
localStorage.setItem('rt_openid', 'oHGap6DNY15882HSxh00rtqxaTHU');
|
||||
} else {
|
||||
let url = `${CutOutQuery(location.href, 'url')}`;
|
||||
console.log(url, 'u---');
|
||||
if (res.message == '微信授权失败, 缺少openid') {
|
||||
window.location.replace(`https://health.ufutx.cn/go/api/h5/v1/wechat/auth?forwardurl=${encodeURIComponent(url)}`);
|
||||
} else {
|
||||
examineRegister(router.currentRoute.value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return Promise.resolve(response);
|
||||
} else {
|
||||
closeToast();
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
},
|
||||
(error: Error) => {
|
||||
if (error.message?.includes('timeout')) {
|
||||
showToast('网络异常,请稍后重试!');
|
||||
}
|
||||
console.log(`err${error}`);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
const request = <T = any>(config: CustomAxiosRequestConfig): Promise<BaseResponse<T>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
service
|
||||
.request<BaseResponse<T>>(config)
|
||||
.then((res) => resolve(res.data))
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
};
|
||||
|
||||
export default request;
|
||||
86
src/utils/service.ts
Normal file
86
src/utils/service.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { ref } from 'vue';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
import qs from 'qs';
|
||||
import { showToast, showLoadingToast, closeToast } from 'vant';
|
||||
import { ContentTypeEnum } from './httpEnum';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
const service = axios.create({
|
||||
// VITE_API_URL || VITE_BASE_API
|
||||
baseURL: import.meta.env.VITE_BASE_API as string, // url = base api url + request url
|
||||
withCredentials: false, // send cookies when cross-domain requests
|
||||
timeout: 15000, // request timeout
|
||||
});
|
||||
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
|
||||
hideLoading?: boolean;
|
||||
}
|
||||
|
||||
// request拦截器 request interceptor
|
||||
service.interceptors.request.use(
|
||||
(config: CustomAxiosRequestConfig) => {
|
||||
// 不传递默认开启loading
|
||||
if (!config.hideLoading) {
|
||||
showLoadingToast({
|
||||
message: '上传中...',
|
||||
forbidClick: true,
|
||||
duration: 0,
|
||||
});
|
||||
}
|
||||
const userStore = useUserStore();
|
||||
if (userStore.token && config.headers) {
|
||||
config.headers['Authorization'] = `Bearer ${userStore.token}`;
|
||||
}
|
||||
if (config.headers) {
|
||||
config.headers['Version'] = `${import.meta.env.VITE_BASE_API_VERSION}`;
|
||||
}
|
||||
const contentType = config.headers?.['content-type'] || config.headers?.['Content-Type'];
|
||||
const data = config.data;
|
||||
if (config.method?.toLocaleUpperCase() == 'POST' && data) {
|
||||
if (ContentTypeEnum.FORM_DATA == contentType) {
|
||||
const fd = new FormData();
|
||||
Object.keys(data).forEach((key) => fd.append(key, data[key]));
|
||||
config.data = fd;
|
||||
} else if (ContentTypeEnum.FORM_URLENCODED == contentType) {
|
||||
config.data = qs.stringify(config.data);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// do something with request error
|
||||
console.log(error); // for debug
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
const error = ref(1);
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
(response) => {
|
||||
closeToast();
|
||||
const res = response.data;
|
||||
if (res.code === 1) {
|
||||
// 服务器访问出错了~
|
||||
showToast(res.message);
|
||||
return Promise.reject(res.message || 'code: 1');
|
||||
} else if (res.code === 2) {
|
||||
// 登录超时,重新登录
|
||||
error.value += 1;
|
||||
if (error.value <= 2) {
|
||||
console.log(error.value, '登录失效,重新登录');
|
||||
}
|
||||
return Promise.reject(res.message);
|
||||
} else {
|
||||
return Promise.resolve(response);
|
||||
}
|
||||
},
|
||||
(error: Error) => {
|
||||
if (error.message?.includes('timeout')) {
|
||||
showToast('请求超时!');
|
||||
}
|
||||
console.log(`err${error}`); // for debug
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
export default service;
|
||||
213
src/views/appDir/appAddAddress.vue
Normal file
213
src/views/appDir/appAddAddress.vue
Normal file
@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<div class="ui-add-address">
|
||||
<div class="ui-mb-40">
|
||||
<div class="ui-address-box">
|
||||
<div class="ui-address-list">
|
||||
<div class="ui-address-name color3 font_28 bold">姓名</div>
|
||||
<van-field v-model="myAddress.name" class="ui-input f-fcc font_28 color3" placeholder="收货人姓名" />
|
||||
</div>
|
||||
<div class="ui-address-list">
|
||||
<div class="ui-address-name color3 font_28 bold">电话号码</div>
|
||||
<van-field v-model="myAddress.mobile" type="number" class="ui-input f-fcc font_28 color3" placeholder="收货人手机号" />
|
||||
</div>
|
||||
<div class="ui-address-list">
|
||||
<div class="ui-address-name color3 font_28 bold">所在地址</div>
|
||||
<van-field v-model="myAddress.more_address" readonly class="ui-input f-fcc font_28 color3" placeholder="请选择地址" @click="showAddress = true" />
|
||||
</div>
|
||||
<div class="ui-address-list ui-address-list-none">
|
||||
<div class="ui-address-name ui-address-nameV2 color3 font_28 bold">详情地址</div>
|
||||
<van-field v-model="myAddress.detail_address" type="textarea" rows="2" class="ui-input f-fcc font_28 color3" placeholder="街道门牌、楼层房间号等信息" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-add-btn font_32 colorF text-center" @click="toAddAddress">保存</div>
|
||||
<van-popup v-model:show="showAddress" round position="bottom" :duration="0.5">
|
||||
<van-picker v-model="payValue" title="选择地址" :columns="options" @confirm="onConfirm" @cancel="showAddress = false" />
|
||||
<!-- <van-cascader-->
|
||||
<!-- v-model="cascaderValue"-->
|
||||
<!-- title="请选择所在地区"-->
|
||||
<!-- :options="options"-->
|
||||
<!-- @close="show = false"-->
|
||||
<!-- @finish="onFinish"-->
|
||||
<!-- />-->
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useCascaderAreaData } from '@vant/area-data';
|
||||
import { showToast } from 'vant';
|
||||
import requestGo from '@/utils/requestApp';
|
||||
import request from '@/utils/request';
|
||||
import router from '@/router';
|
||||
|
||||
defineOptions({ name: 'AppMyAddress' });
|
||||
|
||||
const id = ref<string>('');
|
||||
const throttle = ref(true);
|
||||
const myAddress = ref<any>({});
|
||||
const addressList = ref([]);
|
||||
const showAddress = ref(false);
|
||||
const payValue = ref<any[]>([]);
|
||||
const options = useCascaderAreaData();
|
||||
// 获取地址列表
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/app/user/address/get/detail/${id.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
let result = res.data;
|
||||
myAddress.value = result;
|
||||
if (myAddress.value.province) {
|
||||
myAddress.value.more_address = `${myAddress.value.province}/${myAddress.value.city}/${myAddress.value.county}`;
|
||||
}
|
||||
payValue.value = [`${myAddress.value.province_pid}`, `${myAddress.value.city_pid}`, `${myAddress.value.county_pid}`];
|
||||
console.log(payValue.value, ' payValue.value');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
const toAddAddress = () => {
|
||||
let data = {
|
||||
name: myAddress.value.name,
|
||||
area_code: 86,
|
||||
mobile: myAddress.value.mobile,
|
||||
province: myAddress.value.province,
|
||||
city: myAddress.value.city,
|
||||
county: myAddress.value.county,
|
||||
province_pid: myAddress.value.province_pid - 0,
|
||||
city_pid: myAddress.value.city_pid - 0,
|
||||
county_pid: myAddress.value.county_pid - 0,
|
||||
detail_address: myAddress.value.detail_address,
|
||||
};
|
||||
if (id.value == '0') {
|
||||
data.is_default = 0;
|
||||
requestGo({ url: `/app/user/address/add`, data, method: 'post' })
|
||||
.then((res) => {
|
||||
showToast('添加成功');
|
||||
setTimeout(() => {
|
||||
router.go(-1);
|
||||
}, 1200);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
data.is_default = myAddress.value.is_default;
|
||||
requestGo({ url: `/app/user/address/update/${id.value}`, data, method: 'put' })
|
||||
.then((res) => {
|
||||
showToast('修改成功');
|
||||
setTimeout(() => {
|
||||
router.go(-1);
|
||||
}, 1200);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
const getAddress = () => {
|
||||
request({ url: `get/china`, method: 'get' }).then((res) => {
|
||||
addressList.value = res.data.map((item) => {
|
||||
return {
|
||||
value: item.id,
|
||||
text: item.name,
|
||||
children: getChildren(item.city),
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
const getChildren = (child) => {
|
||||
let children = child.map((item) => {
|
||||
return {
|
||||
value: item.id,
|
||||
text: item.name,
|
||||
children: getChildrenV2(item.county),
|
||||
};
|
||||
});
|
||||
return children;
|
||||
};
|
||||
const getChildrenV2 = (child) => {
|
||||
let children = child.map((item) => {
|
||||
return {
|
||||
value: item.id,
|
||||
text: item.name,
|
||||
};
|
||||
});
|
||||
return children;
|
||||
};
|
||||
// 选择支付方式
|
||||
const onConfirm = ({ selectedValues, selectedOptions }) => {
|
||||
console.log(selectedOptions, 'selectedValues');
|
||||
console.log(selectedValues, 'selectedValues');
|
||||
myAddress.value.province = selectedOptions[0].text;
|
||||
myAddress.value.province_pid = selectedOptions[0].value;
|
||||
myAddress.value.city = selectedOptions[1].text;
|
||||
myAddress.value.city_pid = selectedOptions[1].value;
|
||||
myAddress.value.county = selectedOptions[2].text;
|
||||
myAddress.value.county_pid = selectedOptions[2].value;
|
||||
myAddress.value.more_address = selectedOptions.map((option) => option.text).join('/');
|
||||
showAddress.value = false;
|
||||
// payType.value = selectedValues[0];
|
||||
};
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query as any;
|
||||
id.value = route.id;
|
||||
if (id.value !== '0') {
|
||||
getDetail();
|
||||
}
|
||||
getAddress();
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.ui-add-address {
|
||||
background: #f6f6f6;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
}
|
||||
.ui-address-box {
|
||||
margin: px2rem(16) px2rem(32);
|
||||
padding: 0 px2rem(24);
|
||||
width: px2rem(638);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
.ui-address-list {
|
||||
padding: px2rem(22) 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: px2rem(2) solid #d8d8d8;
|
||||
width: 100%;
|
||||
.ui-address-name {
|
||||
//padding-top: px2rem(32);
|
||||
//padding-bottom: px2rem(32);
|
||||
width: px2rem(112);
|
||||
line-height: px2rem(28);
|
||||
}
|
||||
.ui-input {
|
||||
flex: 1;
|
||||
border-radius: px2rem(16);
|
||||
line-height: px2rem(28);
|
||||
//padding-top: px2rem(26);
|
||||
//padding-bottom: px2rem(26);
|
||||
}
|
||||
}
|
||||
.ui-address-list-none {
|
||||
border: none;
|
||||
align-items: flex-start;
|
||||
.ui-address-nameV2 {
|
||||
padding-top: px2rem(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
.ui-add-btn {
|
||||
position: fixed;
|
||||
bottom: px2rem(84);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: px2rem(686);
|
||||
height: px2rem(88);
|
||||
line-height: px2rem(88);
|
||||
background: linear-gradient(140deg, #18ca6e 0%, #0aa555 100%);
|
||||
border-radius: px2rem(340);
|
||||
}
|
||||
</style>
|
||||
165
src/views/appDir/appMyAddress.vue
Normal file
165
src/views/appDir/appMyAddress.vue
Normal file
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div class="ui-my-address">
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model:loading="loading" :finished="finished" @load="getList">
|
||||
<div class="ui-mb-40">
|
||||
<div v-for="(item, index) in myAddress" :key="index" class="ui-address-box" @click="selectAddress(item, '1')">
|
||||
<img v-if="item.is_default" class="ui-select-icon" src="https://image.fulllinkai.com/202408/09/1d8c1f01ee3e197e38e37f456bd5238f.png" alt="" />
|
||||
<img v-else class="ui-select-icon" src="https://image.fulllinkai.com/202408/09/d7d23faeba28ecfabf21df4a8aa79cce.png" alt="" />
|
||||
<div class="ui-address-message">
|
||||
<div class="ui-address-use f-fc">
|
||||
<div class="ui-address-name ui-mr-32 font_32 ellipsis_1">{{ item.name }}</div>
|
||||
<div class="font_32 color3 ui-mt-4">{{ item.mobile }}</div>
|
||||
</div>
|
||||
<div class="ui-address-content font_24 ellipsis_1">{{ item.province + item.city + item.county + item.detail_address }}</div>
|
||||
</div>
|
||||
<img class="ui-edit-icon" src="https://image.fulllinkai.com/202408/09/cc1fc5018f9def521b5d6d2f8fe4be86.png" alt="" @click.stop="toAddAddress(item.id)" />
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
<div class="ui-add-address font_32 colorF text-center" @click="toAddAddress('0')">添加地址</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { showToast } from 'vant';
|
||||
import requestGo from '@/utils/requestApp';
|
||||
import router from '@/router';
|
||||
|
||||
defineOptions({ name: 'AppMyAddress' });
|
||||
|
||||
const refreshing = ref(false); // 上拉刷新false表示加载完成
|
||||
const finished = ref(false); // true表示数据全部加载完成
|
||||
const loading = ref(false); // false表示数据加载完成
|
||||
const throttle = ref(true);
|
||||
const myAddress = ref<any[]>([]);
|
||||
const selectAddress = (e, type) => {
|
||||
if (throttle.value) {
|
||||
let data = {
|
||||
name: e.name,
|
||||
area_code: 86,
|
||||
mobile: e.mobile,
|
||||
province: e.province,
|
||||
city: e.city,
|
||||
county: e.county,
|
||||
province_pid: e.province_pid - 0,
|
||||
city_pid: e.city_pid - 0,
|
||||
county_pid: e.county_pid - 0,
|
||||
detail_address: e.detail_address,
|
||||
is_default: 1,
|
||||
};
|
||||
throttle.value = false;
|
||||
requestGo({ url: `/app/user/address/update/${e.id}`, data, method: 'put' })
|
||||
.then((res) => {
|
||||
if (type != '0') {
|
||||
// showToast('修改成功');
|
||||
setTimeout(() => {
|
||||
localStorage.setItem('logsiticsAddress', JSON.stringify(data));
|
||||
router.go(-1);
|
||||
}, 300);
|
||||
}
|
||||
// getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
})
|
||||
.finally(() => {
|
||||
throttle.value = true;
|
||||
});
|
||||
}
|
||||
};
|
||||
// 获取地址列表
|
||||
const getList = () => {
|
||||
requestGo({ url: `/app/user/address/get`, method: 'get' })
|
||||
.then((res) => {
|
||||
let result = res.data;
|
||||
myAddress.value = result.data;
|
||||
if (myAddress.value && myAddress.value.length == 1 && myAddress.value.is_default == 0) {
|
||||
selectAddress(myAddress.value[0], '0');
|
||||
}
|
||||
console.log(result);
|
||||
finished.value = true;
|
||||
refreshing.value = false;
|
||||
loading.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
const toAddAddress = (id) => {
|
||||
router.push({
|
||||
name: 'appAddAddress',
|
||||
query: { id },
|
||||
});
|
||||
};
|
||||
// 上拉初始化数据
|
||||
const onRefresh = () => {
|
||||
// loadingState.value = false;
|
||||
myAddress.value = [];
|
||||
// page.value = 1;
|
||||
// noMore.value = false;
|
||||
finished.value = false;
|
||||
loading.value = true;
|
||||
getList();
|
||||
};
|
||||
onMounted(() => {
|
||||
console.log(router.currentRoute.value, 'router.currentRoute.value===');
|
||||
// getList();
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.ui-my-address {
|
||||
background: #f6f6f6;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
}
|
||||
.ui-address-box {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin: px2rem(16) px2rem(32);
|
||||
padding: px2rem(32) px2rem(24);
|
||||
width: px2rem(638);
|
||||
height: px2rem(80);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
.ui-select-icon {
|
||||
width: px2rem(40);
|
||||
height: px2rem(40);
|
||||
}
|
||||
.ui-address-message {
|
||||
flex: 1;
|
||||
margin: px2rem(24) px2rem(16);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
//width: px2rem(500);
|
||||
.ui-address-name {
|
||||
max-width: px2rem(200);
|
||||
color: #3d3d3d;
|
||||
}
|
||||
.ui-address-content {
|
||||
max-width: px2rem(520);
|
||||
color: #888888;
|
||||
}
|
||||
}
|
||||
.ui-edit-icon {
|
||||
width: px2rem(36);
|
||||
height: px2rem(36);
|
||||
}
|
||||
}
|
||||
.ui-add-address {
|
||||
position: fixed;
|
||||
bottom: px2rem(84);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: px2rem(686);
|
||||
height: px2rem(88);
|
||||
line-height: px2rem(88);
|
||||
background: linear-gradient(140deg, #18ca6e 0%, #0aa555 100%);
|
||||
border-radius: px2rem(340);
|
||||
}
|
||||
</style>
|
||||
56
src/views/appDir/appShopAgreement.vue
Normal file
56
src/views/appDir/appShopAgreement.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div class="ui-shopAgreement">
|
||||
<div v-if="policyTitle" class="ui-content">
|
||||
<div class="font_32 bold text-center ui-title">{{ policyTitle }}</div>
|
||||
<richTextParsing :rich-text="policy"></richTextParsing>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestApp';
|
||||
|
||||
defineOptions({ name: 'AppShopAgreement' });
|
||||
|
||||
const id = ref<any>('');
|
||||
const policy = ref<any>('');
|
||||
const policyTitle = ref<any>('');
|
||||
|
||||
// 获取商品详情
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/app/v2/policy/detail/${id.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
policy.value = result.content;
|
||||
policyTitle.value = result.title;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.params;
|
||||
let policyTitle = router.currentRoute.value.query;
|
||||
id.value = route.id;
|
||||
|
||||
getDetail();
|
||||
document.title = policyTitle.title as any;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-shopAgreement {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-content {
|
||||
padding: px2rem(30);
|
||||
|
||||
.ui-title {
|
||||
padding: 0 px2rem(50) px2rem(30) px2rem(50);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
892
src/views/appDir/appShopDetail.vue
Normal file
892
src/views/appDir/appShopDetail.vue
Normal file
@ -0,0 +1,892 @@
|
||||
<template>
|
||||
<div v-if="loading" class="ui-shopDetail">
|
||||
<van-swipe :autoplay="3000" lazy-render>
|
||||
<van-swipe-item v-for="image in banner" :key="image" class="ui-relative">
|
||||
<img class="ui-mall-pic" :src="image" alt="" />
|
||||
</van-swipe-item>
|
||||
<template #indicator="{ active, total }">
|
||||
<div class="custom-indicator font_26 colorF">{{ active + 1 }}/{{ total }}</div>
|
||||
</template>
|
||||
</van-swipe>
|
||||
<div class="ui-shop-detail-container">
|
||||
<div class="ui-shop-data-box">
|
||||
<div class="f-fcl">
|
||||
<span class="font_28 ui-price-symbol bold">¥</span>
|
||||
<div class="font_44 ui-show-price bold"><span v-html="htmlPrice"></span></div>
|
||||
<div class="font_28 ui-original-price color6">¥{{ originPrice }}</div>
|
||||
</div>
|
||||
<div class="font_32 color3 bold ui-pt-10">{{ title }}</div>
|
||||
<!-- <div class="font_24 color9 ui-pt-20">通过无抗生素产品认证,个个可...</div>-->
|
||||
</div>
|
||||
<div class="ui-ExpressDelivery-data-box">
|
||||
<div>
|
||||
<div class="f-fcl font_28">
|
||||
<span class="color9 ui-pr-24">配送</span>
|
||||
<span class="ui-pr-24">广东深圳</span>
|
||||
<span v-if="freightPrice != '0.00' || freightPrice != 0" class="ui-pl-24 ui-relative ui-distribution-address">运费:{{ freightPrice }}</span>
|
||||
</div>
|
||||
<!-- <div class="font_28 ui-pt-24">-->
|
||||
<!-- <span class="color9 ui-pr-24">服务</span>-->
|
||||
<!-- <span class="color3">支持7天无理由退货</span>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="describe" class="ui-relative ui-pt-40">
|
||||
<img class="ui-line-icon" src="https://image.fulllinkai.com/202405/15/266a22038e0122c70fc282f00c78dbc7.png" alt="" />
|
||||
<div class="font_26 color3 ui-line-text">商品详情</div>
|
||||
</div>
|
||||
<div v-if="describe" class="font_28 color3 ui-detail-introduce">
|
||||
<richTextParsing :rich-text="describe"></richTextParsing>
|
||||
</div>
|
||||
<div class="ui-bottom-operation text-center">
|
||||
<div class="ui-buy-btn font_30 colorF" @click="showBug = true">立即购买</div>
|
||||
</div>
|
||||
<sharePosterV2 ref="openSharePoster">
|
||||
<template #sharePoster>
|
||||
<!--生成海报html容器-->
|
||||
<div id="capture" class="ui-poster-container">
|
||||
<div class="ui-user-avatar-box f-fcc">
|
||||
<div class="ui-user-avatar backCover" :style="{ background: 'url(' + canvasData.avatar + ')' }"></div>
|
||||
<div class="color3 font_22 ui-ml-8 ui-user-name-box f-fcc">
|
||||
<div v-if="shareName">{{ shareName }}</div>
|
||||
<div>推荐一个好物给你</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-poster-pic-box">
|
||||
<img class="ui-poster-pic" :src="canvasData.pic" alt="" />
|
||||
</div>
|
||||
<div class="ui-poster-data-box">
|
||||
<div class="ui-mt-20 ui-ml-20">
|
||||
<div class="f-fcl">
|
||||
<span class="font_24 ui-poster-price-symbol">¥</span>
|
||||
<div class="font_40 ui-poster-price"><span v-html="htmlSharePrice"></span></div>
|
||||
</div>
|
||||
<div class="font_24 ellipsis_2 ui-poster-title color3">{{ title }}</div>
|
||||
</div>
|
||||
<div class="ui-poster-qrcode-box">
|
||||
<img class="ui-poster-qrcode" :src="canvasData.qrcode" alt="" />
|
||||
<div class="font_20 color6 text-center">长按保存图片至相册</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</sharePosterV2>
|
||||
<van-popup v-model:show="showBug" round position="bottom" :duration="0.5">
|
||||
<div class="ui-bug-box">
|
||||
<img class="ui-close-icon" src="https://image.fulllinkai.com/202405/16/20161b3e74af1eacd328181ff40b0358.png" alt="" @click="showBug = false" />
|
||||
<div class="ui-buy-detail-box">
|
||||
<img class="ui-buy-pic" :src="icon" alt="" />
|
||||
<div>
|
||||
<div class="ellipsis_2 font_32 color333 bold ui-buy-title">{{ title }}</div>
|
||||
<div class="f-fcl ui-buy-price color3 font_24"> 已选:{{ spuData.spec[spuIndex].name }} {{ spuSubIndex !== null ? spuSubData.spec[spuSubIndex].name : '' }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="spuData.name" class="ui-sku-box">
|
||||
<div class="ui-sku-list">
|
||||
<div class="font_28 color3 bold">{{ spuData.name }}</div>
|
||||
<div class="f-fcl f-wrap">
|
||||
<div v-for="(item, index) in spuData.spec" :key="index" class="font_26 f-fbc color3 ui-pt-16" @click="selectSku(index)">
|
||||
<div class="ui-sku-item" :class="spuIndex == index ? 'ui-sku-item-active colorF' : 'color3'">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="spuSubData.name" class="ui-pt-36">
|
||||
<div class="font_28 color3 bold">{{ spuSubData.name }}</div>
|
||||
<div class="f-fcl f-wrap">
|
||||
<div v-for="(item, index) in spuSubData.spec" :key="index" class="font_26 f-fbc color3 ui-pt-16" @click="selectSubSku(index)">
|
||||
<div class="ui-sku-item" :class="spuSubIndex == index ? 'ui-sku-item-active colorF' : 'color3'">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-num-box f-fbc ui-pt-28">
|
||||
<div class="font_24 color6"><span class="font_28 color3 ui-mr-16">数量</span>库存:{{ stock }}</div>
|
||||
<div class="f-fcr ui-num-input-box">
|
||||
<div class="ui-relative f-fcl">
|
||||
<div class="font_40 color6 ui-num-input-minus" @click="numMinus()">
|
||||
<div class="ui-num-minus">-</div>
|
||||
</div>
|
||||
<div class="ui-select-input font_28">{{ num }}</div>
|
||||
<div class="font_40 color6 ui-num-input-add" @click="numAdd()">
|
||||
<div class="ui-num-minus-v2">+</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-total-price-box">
|
||||
<div class="f-fcl">
|
||||
<div class="font_24 color6">合计金额:</div>
|
||||
<div v-if="calculating" class="font_26 color6 bold">计算中...</div>
|
||||
<div v-else-if="num == 0" class="font_26 color6 bold">库存不足</div>
|
||||
<div v-else class="f-fcl bold ui-total-price">
|
||||
<span class="font_28 ui-buy-price-symbol">¥</span>
|
||||
<div class="font_44"><span v-html="htmlTotalPrice"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="policyTitle" class="ui-confirm-bottom-box">
|
||||
<div class="f-fcc">
|
||||
<img v-show="!isAgreement" class="ui-agreement-icon" src="https://image.fulllinkai.com/202405/16/fae039c670338fe6743b7f6a8803ec43.png" alt="" @click="isAgreement = !isAgreement" />
|
||||
<img v-show="isAgreement" class="ui-agreement-icon" src="https://image.fulllinkai.com/202408/15/e536a423a145ae12ab4f6dc57f58588d.png" alt="" @click="isAgreement = !isAgreement" />
|
||||
<div class="font_24 color6" @click="isAgreement = !isAgreement">
|
||||
已阅读并同意<span class="ui-agreement-text" @click.stop="jumpAgreement">{{ policyTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-confirm-btn font_32 f-fcc colorF bold" @click="payment">立即支付</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, onDeactivated, onActivated, onUnmounted } from 'vue';
|
||||
import { showToast } from 'vant';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestApp';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
defineOptions({ name: 'ShopDetail' });
|
||||
|
||||
const userStore = useUserStore() as any;
|
||||
const loading = ref(false);
|
||||
const showBug = ref(false);
|
||||
const timer = ref<any>(null);
|
||||
const isAgreement = ref(false); // 是否同意协议
|
||||
|
||||
const id = ref<any>('');
|
||||
const title = ref<any>('');
|
||||
const icon = ref<any>('');
|
||||
const policyId = ref<any>('');
|
||||
const policyTitle = ref<any>('');
|
||||
const banner = ref<any[]>([]); // 轮播图
|
||||
const describe = ref<any>(); // 详情富文本
|
||||
const num = ref<any>(0); // 购买数量
|
||||
const skuIds = ref<any>('');
|
||||
const skuIdDataList = ref<any[]>([]);
|
||||
const stock = ref<any>(0); // 选中的sku剩余库存
|
||||
const calculating = ref<any>(false); // 是否显示价格计算中
|
||||
|
||||
const spuData = ref<any>({}); // spu一级数据
|
||||
const spuSubData = ref<any>({}); // spu二级数据
|
||||
|
||||
const spuIndex = ref(0); // spu一级选中下标
|
||||
const spuSubIndex = ref<any>(null); // spu二级选中下标
|
||||
const defaultSkuId = ref<any>(0); // 默认sku_id
|
||||
const querySkuId = ref<any>(0); // 路径sku_id
|
||||
|
||||
const htmlPrice = ref<any>(''); // 详情展示价格
|
||||
const htmlSharePrice = ref<any>(''); // 分享展示价格
|
||||
const shareName = ref<any>('');
|
||||
const htmlTotalPrice = ref<any>('0'); // 总价展示价格
|
||||
const originPrice = ref<any>(0); // 原价
|
||||
const freightPrice = ref<any>(0); // 邮费
|
||||
|
||||
const canvasData = ref<any>({ background: '', avatar: '', pic: '', qrcode: '' }); // 分享所需要的图片数据
|
||||
const openSharePoster = ref<any>(); // 分享按钮组件事件
|
||||
|
||||
// 获取商品详情
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/app/v2/shop/common/spu/detail/${id.value}`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
|
||||
banner.value = [];
|
||||
result.spu.banner = JSON.parse(result.spu.banner);
|
||||
if (result.spu.banner && result.spu.banner.length > 0) {
|
||||
banner.value = result.spu.banner;
|
||||
} else {
|
||||
banner.value.push(result.spu.icon);
|
||||
}
|
||||
describe.value = result.spu.description;
|
||||
title.value = result.spu.title;
|
||||
icon.value = result.spu.icon;
|
||||
policyId.value = result.spu.policy_id;
|
||||
policyTitle.value = result.spu.policy_title;
|
||||
|
||||
result.spu.spec = JSON.parse(result.spu.spec);
|
||||
spuData.value = result.spu.spec;
|
||||
|
||||
spuSubData.value = {};
|
||||
// 默认选中第一个sku
|
||||
if (spuData.value.name && spuData.value.spec[spuIndex.value].sub_spec) {
|
||||
spuSubData.value = spuData.value.spec[spuIndex.value].sub_spec;
|
||||
spuSubIndex.value = 0;
|
||||
}
|
||||
// 默认的sku_id
|
||||
defaultSkuId.value = result.sku_default?.id || 0;
|
||||
skuIds.value = '';
|
||||
// 循环出所有的skuid
|
||||
spuData.value.spec.forEach((item) => {
|
||||
if (item.skuid) {
|
||||
skuIds.value += `${skuIds.value ? ',' : ''}${item.skuid}`;
|
||||
}
|
||||
if (item.sub_spec) {
|
||||
recursion(item);
|
||||
}
|
||||
});
|
||||
|
||||
if (`${result.sku_default.price}`.includes('.')) {
|
||||
let splitPrice = result.sku_default.price.split('.');
|
||||
htmlSharePrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlSharePrice.value = result.sku_default.price;
|
||||
}
|
||||
|
||||
shareName.value = userStore.agentName ? (userStore.agentName.length > 4 ? `${userStore.agentName.slice(0, 4)}...` : userStore.agentName) : '';
|
||||
|
||||
// 根据循环出所有的skuid获取每一个skuid的库存
|
||||
getSkuIdStock();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取所有skuid库存
|
||||
const getSkuIdStock = () => {
|
||||
requestGo({ url: `/app/v2/shop/common/sku/${skuIds.value}`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
console.log(result, '77777');
|
||||
skuIdDataList.value = result;
|
||||
|
||||
if (skuIdDataList.value && skuIdDataList.value.length > 0) {
|
||||
// 判断路径 sku_id是否存在sku列表中
|
||||
skuIdDataList.value.map((item) => {
|
||||
if (item.id == querySkuId.value) {
|
||||
defaultSkuId.value = querySkuId.value;
|
||||
}
|
||||
});
|
||||
|
||||
spuData.value.spec.map((item, index) => {
|
||||
if (item.sub_spec) {
|
||||
item.sub_spec.spec.map((itemV2, indexV2) => {
|
||||
if (defaultSkuId.value == itemV2.skuid) {
|
||||
spuIndex.value = index;
|
||||
spuSubIndex.value = indexV2;
|
||||
spuSubData.value = item.sub_spec;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (defaultSkuId.value == item.skuid) {
|
||||
spuIndex.value = index;
|
||||
}
|
||||
}
|
||||
});
|
||||
gainSelectStock();
|
||||
}
|
||||
|
||||
num.value = 1;
|
||||
prepay('init');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取选中的sku库存
|
||||
const gainSelectStock = () => {
|
||||
let id;
|
||||
if (spuSubIndex.value !== null) {
|
||||
id = spuSubData.value.spec[spuSubIndex.value].skuid;
|
||||
} else {
|
||||
id = spuData.value.spec[spuIndex.value].skuid;
|
||||
}
|
||||
skuIdDataList.value.forEach((item) => {
|
||||
if (item.id == id) {
|
||||
stock.value = item.stock;
|
||||
originPrice.value = item.price;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 递归循环所有skuid
|
||||
const recursion = (e) => {
|
||||
e.sub_spec.spec.forEach((item) => {
|
||||
if (item.skuid) {
|
||||
skuIds.value += `${skuIds.value ? ',' : ''}${item.skuid}`;
|
||||
}
|
||||
if (item.sub_spec) {
|
||||
recursion(item.sub_spec.spec);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取预计算价格
|
||||
const prepay = (e) => {
|
||||
let id = '';
|
||||
if (spuSubIndex.value !== null) {
|
||||
id = spuSubData.value.spec[spuSubIndex.value].skuid;
|
||||
} else {
|
||||
id = spuData.value.spec[spuIndex.value].skuid;
|
||||
}
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => {
|
||||
requestGo({ url: `/app/v2/shop/common/sku/prepay/${id}/${e == 'init' ? 1 : num.value}/1`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
// originPrice.value = result.price_origin;
|
||||
freightPrice.value = result.freight;
|
||||
loading.value = true;
|
||||
if (e == 'init') {
|
||||
if (`${result.price}`.includes('.')) {
|
||||
let splitPrice = result.price.split('.');
|
||||
htmlPrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlPrice.value = result.price;
|
||||
}
|
||||
if (!stock.value) {
|
||||
num.value = 0;
|
||||
}
|
||||
}
|
||||
if (`${result.price}`.includes('.')) {
|
||||
let splitPrice = result.price.split('.');
|
||||
htmlTotalPrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
htmlPrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlTotalPrice.value = result.price;
|
||||
htmlPrice.value = result.price;
|
||||
}
|
||||
calculating.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// Sku 数量减少
|
||||
const numMinus = () => {
|
||||
if (num.value <= 1) {
|
||||
return;
|
||||
}
|
||||
num.value--;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
};
|
||||
|
||||
// Sku 数量增加
|
||||
const numAdd = () => {
|
||||
if (num.value >= stock.value) {
|
||||
showToast('超出限购或商品库存上限');
|
||||
return;
|
||||
}
|
||||
num.value++;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
};
|
||||
|
||||
// 支付
|
||||
const payment = () => {
|
||||
let data = {} as any;
|
||||
let spuId;
|
||||
if (spuSubIndex.value !== null) {
|
||||
spuId = spuSubData.value.spec[spuSubIndex.value].skuid;
|
||||
} else {
|
||||
spuId = spuData.value.spec[spuIndex.value].skuid;
|
||||
}
|
||||
|
||||
data.id = id.value;
|
||||
data.skuId = spuId;
|
||||
data.spuNum = num.value;
|
||||
data.spuName = spuData.value.spec[spuIndex.value].name;
|
||||
data.spuSubName = spuSubIndex.value !== null ? spuSubData.value.spec[spuSubIndex.value].name : '';
|
||||
|
||||
if (num.value <= 0) {
|
||||
showToast('请先选择购买数量');
|
||||
return;
|
||||
}
|
||||
|
||||
if (policyTitle.value && !isAgreement.value) {
|
||||
showToast('请先阅读并同意协议');
|
||||
return;
|
||||
}
|
||||
|
||||
router.push({
|
||||
name: 'appShopOrderConfirm',
|
||||
query: { orderData: JSON.stringify(data) },
|
||||
});
|
||||
};
|
||||
|
||||
const selectSku = (index) => {
|
||||
if (spuIndex.value == index) {
|
||||
return;
|
||||
}
|
||||
htmlTotalPrice.value = '0';
|
||||
spuIndex.value = index;
|
||||
if (spuData.value.spec[index].sub_spec) {
|
||||
spuSubData.value = spuData.value.spec[index].sub_spec;
|
||||
spuSubIndex.value = 0;
|
||||
} else {
|
||||
spuSubData.value = {};
|
||||
spuSubIndex.value = null;
|
||||
}
|
||||
|
||||
num.value = 0;
|
||||
if (skuIdDataList.value && skuIdDataList.value.length > 0) {
|
||||
gainSelectStock();
|
||||
}
|
||||
|
||||
if (stock.value) {
|
||||
num.value = 1;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
}
|
||||
};
|
||||
|
||||
const selectSubSku = (index) => {
|
||||
if (spuSubIndex.value == index) {
|
||||
return;
|
||||
}
|
||||
htmlTotalPrice.value = '0';
|
||||
spuSubData.value = spuData.value.spec[spuIndex.value].sub_spec;
|
||||
spuSubIndex.value = index;
|
||||
num.value = 0;
|
||||
|
||||
if (skuIdDataList.value && skuIdDataList.value.length > 0) {
|
||||
gainSelectStock();
|
||||
}
|
||||
|
||||
if (stock.value) {
|
||||
num.value = 1;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
}
|
||||
};
|
||||
|
||||
const jumpAgreement = () => {
|
||||
router.push({
|
||||
name: 'appShopAgreement',
|
||||
params: { id: policyId.value },
|
||||
query: { title: policyTitle.value },
|
||||
});
|
||||
};
|
||||
|
||||
// 离开时清除生成的海报
|
||||
onDeactivated(() => {
|
||||
// window.removeEventListener('popstate', handleBackButton);
|
||||
// window.removeEventListener('backbutton', handleBackButton, false);
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
let route = router.currentRoute.value.params;
|
||||
let query = router.currentRoute.value.query;
|
||||
if (id.value != (route.id || 102)) {
|
||||
id.value = route.id;
|
||||
loading.value = false;
|
||||
showBug.value = false;
|
||||
spuIndex.value = 0;
|
||||
spuSubIndex.value = null;
|
||||
querySkuId.value = query?.sku_id || 0;
|
||||
getDetail();
|
||||
}
|
||||
});
|
||||
|
||||
// const handleBackButton = () => {
|
||||
// // 这里需要添加实际的返回逻辑,比如判断当前页面栈等
|
||||
// alert('1');
|
||||
// if (window.history.length > 1) {
|
||||
// window.webAppInterface.goBack();
|
||||
// } else {
|
||||
// alert('2');
|
||||
// //这个可以关闭安卓系统的手机
|
||||
// document.addEventListener(
|
||||
// 'WeixinJSBridgeReady',
|
||||
// function () {
|
||||
// WeixinJSBridge.call('closeWindow');
|
||||
// },
|
||||
// false,
|
||||
// );
|
||||
// // 如果已经是首页,可以选择退出应用或进行其他操作
|
||||
// // 例如:navigator.app.exitApp() 如果是 Cordova 应用等
|
||||
// }
|
||||
// };
|
||||
|
||||
onMounted(() => {
|
||||
// window.addEventListener('popstate', handleBackButton);
|
||||
// window.addEventListener('backbutton', handleBackButton, false);
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-shopDetail {
|
||||
background: #f4f4f4;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-mall-pic {
|
||||
width: 100vw;
|
||||
height: px2rem(750);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.custom-indicator {
|
||||
position: absolute;
|
||||
right: px2rem(20);
|
||||
bottom: px2rem(20);
|
||||
border-radius: px2rem(8);
|
||||
padding: px2rem(8) px2rem(14);
|
||||
letter-spacing: px2rem(4);
|
||||
background: #aaaaaa;
|
||||
}
|
||||
|
||||
.ui-shop-detail-container {
|
||||
padding: px2rem(24);
|
||||
|
||||
.ui-shop-data-box,
|
||||
.ui-ExpressDelivery-data-box {
|
||||
padding: px2rem(30) px2rem(24);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
margin-bottom: px2rem(24);
|
||||
|
||||
.ui-price-symbol {
|
||||
margin-right: px2rem(2);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-show-price,
|
||||
.ui-price-symbol {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-original-price {
|
||||
text-decoration: line-through;
|
||||
margin-left: px2rem(16);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-ExpressDelivery-data-box {
|
||||
.ui-distribution-address:after {
|
||||
content: '';
|
||||
width: px2rem(2);
|
||||
height: px2rem(22);
|
||||
background: #d8d8d8;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: px2rem(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-line-icon {
|
||||
width: px2rem(310);
|
||||
height: px2rem(12);
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.ui-line-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: px2rem(28);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.ui-detail-introduce {
|
||||
padding: px2rem(20) 0 px2rem(120) 0;
|
||||
background: #ffffff;
|
||||
margin-top: px2rem(30);
|
||||
}
|
||||
|
||||
.ui-bottom-operation {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
padding: px2rem(18) 0 px2rem(42) 0;
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-top: px2rem(2) solid #f5f5f5;
|
||||
|
||||
.ui-operation-icon-box {
|
||||
flex: 1;
|
||||
|
||||
.ui-operation-icon {
|
||||
width: px2rem(44);
|
||||
height: px2rem(44);
|
||||
display: block;
|
||||
margin: 0 auto px2rem(2) auto;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-btn {
|
||||
margin: 0 auto;
|
||||
width: px2rem(520);
|
||||
height: px2rem(88);
|
||||
line-height: px2rem(88);
|
||||
background: linear-gradient(140deg, #18ca6e 0%, #0aa555 100%);
|
||||
border-radius: px2rem(44);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-poster-container {
|
||||
position: relative;
|
||||
position: fixed;
|
||||
top: -100000;
|
||||
left: 0;
|
||||
z-index: -99999;
|
||||
border-radius: px2rem(16);
|
||||
width: px2rem(482);
|
||||
height: px2rem(806);
|
||||
padding: 0 px2rem(30) px2rem(30) px2rem(30);
|
||||
background: #f7f7f7;
|
||||
box-sizing: border-box;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
|
||||
.ui-user-avatar-box {
|
||||
width: px2rem(440);
|
||||
height: px2rem(48);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(40);
|
||||
margin-top: px2rem(8);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: px2rem(10);
|
||||
z-index: 10;
|
||||
|
||||
.ui-user-avatar {
|
||||
width: px2rem(28);
|
||||
height: px2rem(28);
|
||||
border-radius: 50%;
|
||||
margin-left: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-user-name-box {
|
||||
margin-top: px2rem(-6);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-poster-pic-box,
|
||||
.ui-poster-data-box {
|
||||
width: px2rem(450);
|
||||
height: px2rem(450);
|
||||
border-radius: px2rem(16);
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
top: px2rem(80);
|
||||
left: px2rem(16);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-poster-pic {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: px2rem(16);
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-poster-data-box {
|
||||
top: px2rem(546);
|
||||
height: px2rem(244);
|
||||
|
||||
.ui-poster-title {
|
||||
width: px2rem(226);
|
||||
line-height: px2rem(36);
|
||||
max-width: px2rem(226);
|
||||
margin-top: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-poster-price,
|
||||
.ui-poster-price-symbol {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-poster-price-symbol {
|
||||
margin-right: px2rem(2);
|
||||
margin-top: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-poster-qrcode-box {
|
||||
.ui-poster-qrcode {
|
||||
width: px2rem(200);
|
||||
height: px2rem(200);
|
||||
border-radius: px2rem(16);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
margin-bottom: px2rem(-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-bug-box {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding-bottom: px2rem(60);
|
||||
border-radius: px2rem(24);
|
||||
|
||||
.ui-close-icon {
|
||||
position: absolute;
|
||||
right: px2rem(24);
|
||||
top: px2rem(24);
|
||||
z-index: 22;
|
||||
width: px2rem(48);
|
||||
height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-buy-detail-box {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
height: px2rem(160);
|
||||
position: relative;
|
||||
padding: px2rem(30) px2rem(30) 0 px2rem(30);
|
||||
|
||||
.ui-buy-pic {
|
||||
width: px2rem(160);
|
||||
min-width: px2rem(160);
|
||||
height: px2rem(160);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
margin-right: px2rem(16);
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
}
|
||||
|
||||
.ui-buy-title {
|
||||
max-width: px2rem(440);
|
||||
line-height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-buy-price {
|
||||
position: absolute;
|
||||
bottom: px2rem(-12);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-price-symbol {
|
||||
margin-right: px2rem(2);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-total-price-box {
|
||||
padding-top: px2rem(40);
|
||||
|
||||
.ui-total-price {
|
||||
color: #cc352f;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-user-input {
|
||||
width: px2rem(532);
|
||||
box-sizing: border-box;
|
||||
border: px2rem(2) solid #f5f5f5;
|
||||
border-radius: px2rem(16);
|
||||
padding: px2rem(16) px2rem(30);
|
||||
}
|
||||
|
||||
::v-deep(input::-webkit-input-placeholder) {
|
||||
font-weight: initial;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
// 去除默认下划线
|
||||
::v-deep(.van-cell:after) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-sku-box {
|
||||
padding: px2rem(40) px2rem(30) px2rem(24) px2rem(30);
|
||||
|
||||
.ui-sku-list {
|
||||
.ui-sku-item,
|
||||
.ui-sku-item-active {
|
||||
padding: px2rem(12) px2rem(24);
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-sku-item-active {
|
||||
background: linear-gradient(140deg, #18ca6e 0%, #0aa555 100%);
|
||||
}
|
||||
|
||||
.ui-active-sku {
|
||||
background: #e8fff7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-num-box {
|
||||
.ui-num-input-box {
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #ececec;
|
||||
|
||||
.ui-num-input-minus,
|
||||
.ui-num-input-add {
|
||||
width: px2rem(56);
|
||||
height: px2rem(56);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.ui-num-minus,
|
||||
.ui-num-minus-v2 {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.ui-num-minus {
|
||||
top: 43%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-num-input-minus {
|
||||
border-right: px2rem(2) solid #ececec;
|
||||
}
|
||||
|
||||
.ui-num-input-add {
|
||||
border-left: px2rem(2) solid #ececec;
|
||||
}
|
||||
|
||||
.ui-select-input {
|
||||
width: px2rem(44);
|
||||
border: none;
|
||||
text-align: center;
|
||||
padding: px2rem(4) px2rem(20);
|
||||
background: initial;
|
||||
line-height: px2rem(40);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-confirm-btn {
|
||||
width: px2rem(638);
|
||||
height: px2rem(88);
|
||||
background: linear-gradient(140deg, #18ca6e 0%, #0aa555 100%);
|
||||
border-radius: px2rem(24);
|
||||
margin: px2rem(28) auto 0 auto;
|
||||
}
|
||||
|
||||
.ui-confirm-bottom-box {
|
||||
padding-top: px2rem(28);
|
||||
border-top: px2rem(2) solid #eaeaea;
|
||||
|
||||
.ui-agreement-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
margin-right: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-agreement-text {
|
||||
color: #18ca6e;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
633
src/views/appDir/appShopOrderConfirm.vue
Normal file
633
src/views/appDir/appShopOrderConfirm.vue
Normal file
@ -0,0 +1,633 @@
|
||||
<template>
|
||||
<div v-if="loading" class="ui-shopOrderConfirm">
|
||||
<div class="ui-m-inf">
|
||||
<div class="ui-relative">
|
||||
<div class="f-fbc">
|
||||
<div v-for="(item, index) in receivingList" :key="index" class="font_28 f-fcc ui-receiving-item" :class="receivingIndex == index ? 'colorAppGreen font_30 bold' : 'color3'" @click="selectSymptom(index)">
|
||||
<div class="ui-receiving-text">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img v-show="receivingIndex == 0" class="ui-receiving-icon" src="https://image.fulllinkai.com/202404/09/122fe1183af7e8e15dfa3ea4b5ba861f.png" alt="" @click="selectSymptom(1)" />
|
||||
<img v-show="receivingIndex == 1" class="ui-receiving-icon-v2" src="https://image.fulllinkai.com/202404/09/64e3443b623f73dd341389fc53e303e8.png" alt="" @click="selectSymptom(0)" />
|
||||
</div>
|
||||
<div class="ui-address-box">
|
||||
<div v-if="receivingIndex == 0">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">自提地址:</div>
|
||||
<div class="font_28 color3 ui-address-content">广东省深圳市南山区南新路阳光科创中心B座33楼3301(荔林地铁站C口步行170米)</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/3b4a522e6bdb081a14186712f87cb20b.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">联系人:</div>
|
||||
<div class="font_28 color3 ui-address-content">友福客服,17788799376</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else @click="openWx">
|
||||
<div v-if="detailedAddress">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">收货地址:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ detailedAddress }}</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/3b4a522e6bdb081a14186712f87cb20b.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">收货人:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ address.userName }},{{ address.telNumber }}</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="ui-address-item ui-pt-6 ui-pb-32">
|
||||
<div class="font_28 color3 bold">点击添加收货地址</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <img class="ui-decoration-icon" src="https://image.fulllinkai.com/202309/20/e8a30e7308236eb3894fec737b66657d.png" alt="" />-->
|
||||
</div>
|
||||
<div v-if="receivingIndex == 0" class="ui-remark-box ui-address-box font_28">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">自提人:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ userDetail.name }},{{ userDetail.mobile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-inf-box">
|
||||
<div class="ui-m-avt-lst ui-relative">
|
||||
<img class="ui-pic" :src="icon" alt="" />
|
||||
<div class="ui-m-lst-ri">
|
||||
<div class="font_32 ellipsis_2 bold ui-title">{{ title }}</div>
|
||||
<div class="font_28 ui-product-spu-name color6">已选:{{ orderData.spuName }}{{ orderData.spuSubName ? ';' + orderData.spuSubName : '' }}</div>
|
||||
<div class="font_28 color3 ui-product-num">X {{ orderData.spuNum }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-mt-40">
|
||||
<div class="font_28 color3">商品总额</div>
|
||||
<div class="font_28 bold"><span class="ui-buy-price-symbol">¥</span>{{ totalPrices }}</div>
|
||||
</div>
|
||||
<div v-if="receivingIndex != 0" class="f-fbc ui-mt-20">
|
||||
<div class="font_28 color3">快递费用</div>
|
||||
<div class="font_28"><span class="ui-buy-price-symbol">¥</span>{{ freightPrice }}</div>
|
||||
</div>
|
||||
<!-- <div v-if="related.share_user_name || related.invite_user_name || related.referrer_user_name">-->
|
||||
<!-- <div v-if="related.share_user_name" class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">分享用户</div>-->
|
||||
<!-- <div class="font_28 bold color6">{{ related.share_user_name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="related.invite_user_name" class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">邀请用户</div>-->
|
||||
<!-- <div class="font_28 bold color6">{{ related.invite_user_name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="related.referrer_user_name" class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">推荐用户</div>-->
|
||||
<!-- <div class="font_28 bold color6">{{ related.referrer_user_name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-else>-->
|
||||
<!-- <div class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">关联信息</div>-->
|
||||
<!-- <div class="font_28 bold color6">暂无关联信息</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="f-fbc ui-mt-20">-->
|
||||
<!-- <div class="font_28 color3">服务</div>-->
|
||||
<!-- <div class="font_28">七天无理由退货</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="ui-discounts-box f-fbc">
|
||||
<div></div>
|
||||
<div class="f-fcr">
|
||||
<div class="font_28 color3">应付金额:</div>
|
||||
<div class="f-fcl ui-buy-price">
|
||||
<span class="font_28 ui-buy-price-symbol bold">¥</span>
|
||||
<div class="font_32 bold"><span v-html="htmlTotalPrices"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-remark-box font_28 f-fbc" @click="showRemark = true">
|
||||
<div class="color3">订单备注</div>
|
||||
<div class="ui-remark-text">
|
||||
<div class="f-fcr text-right">
|
||||
<div class="ui-mr-10 ellipsis_1" :class="remark ? 'color3' : 'color6'">{{ remark ? remark : '请填写备注' }}</div>
|
||||
<img class="ui-remark-triangle-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-operation-box f-fbc">
|
||||
<div class="font_24 color3 f-fcl">
|
||||
合计:
|
||||
<div class="f-fcl ui-buy-price">
|
||||
<span class="font_28 ui-buy-price-symbol bold">¥</span>
|
||||
<div class="font_44 bold"><span v-html="htmlTotalPrices"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-buy-btn f-fcc colorF font_30 bold" @click="payment">确认支付</div>
|
||||
</div>
|
||||
<van-popup v-model:show="showRemark" round position="bottom" :duration="0.5">
|
||||
<div class="ui-remark-input-box">
|
||||
<img class="ui-close-icon" src="https://image.fulllinkai.com/202405/16/20161b3e74af1eacd328181ff40b0358.png" alt="" @click="(showRemark = false), (remark = '')" />
|
||||
<div class="text-center color3 font_32 bold">订单备注</div>
|
||||
<van-field v-model="remark" type="textarea" autosize rows="5" show-word-limit class="ui-remark-input f-fcc font_40 color3 bold" :maxlength="200" placeholder="请填写备注" />
|
||||
<div class="font_32 colorF f-fcc ui-remark-btn" @click="showRemark = false">确认</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { closeToast, showToast, showDialog } from 'vant';
|
||||
import wx from 'weixin-js-sdk';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestApp';
|
||||
import request from '@/utils/requestAppPHP';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
defineOptions({ name: 'ShopOrderConfirm' });
|
||||
const isIOS = ref<any>(null);
|
||||
const userStore = useUserStore() as any;
|
||||
const throttle = ref(true);
|
||||
const orderData = ref<any>({});
|
||||
const loading = ref<any>(false);
|
||||
const timer = ref<any>(null);
|
||||
|
||||
const receivingIndex = ref(1);
|
||||
const receivingList = ref<any[]>(['线下自提', '物流配送']);
|
||||
|
||||
const related = ref<any>({}); // 关联分享、推荐、介绍用户信息
|
||||
const title = ref<any>('');
|
||||
const icon = ref<any>('');
|
||||
const showRemark = ref(false);
|
||||
const remark = ref<any>('');
|
||||
|
||||
const totalPrices = ref<any>(0); // 合计价格
|
||||
const htmlTotalPrices = ref<any>(0); // 合计价格小数点字号
|
||||
const freightPrice = ref<any>(0); // 邮费
|
||||
const totalNumber = ref<any>(0);
|
||||
|
||||
const wxPay = ref<any>(null); // 支付所需config
|
||||
const tradeId = ref<any>(''); // 订单ID
|
||||
const tradeNo = ref<any>(''); // 订单号
|
||||
|
||||
const detailedAddress = ref<any>('');
|
||||
const address = ref<any>({
|
||||
userName: '',
|
||||
postalCode: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
countyName: '',
|
||||
detailInfo: '',
|
||||
nationalCode: '',
|
||||
telNumber: '',
|
||||
});
|
||||
|
||||
// 获取商品详情
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/app/v2/shop/common/spu/detail/${orderData.value.id}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
title.value = result.spu.title;
|
||||
icon.value = result.spu.icon;
|
||||
related.value = result.related_person_detail;
|
||||
// 获取上一次记录的物流配送地址
|
||||
if (result.recive && result.recive.address) {
|
||||
address.value.userName = result.recive.name;
|
||||
address.value.telNumber = result.recive.mobile;
|
||||
detailedAddress.value = result.recive.address;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取预计算价格
|
||||
const prepay = () => {
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => {
|
||||
requestGo({ url: `/app/v2/shop/common/sku/prepay/${orderData.value.skuId}/${orderData.value.spuNum}/${receivingIndex.value == 0 ? 1 : 2}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
freightPrice.value = result.freight;
|
||||
totalNumber.value = result.total_number;
|
||||
loading.value = true;
|
||||
// 小数点后面字号变小
|
||||
if (`${result.total}`.includes('.')) {
|
||||
let splitPrice = result.total.split('.');
|
||||
htmlTotalPrices.value = `${splitPrice[0]}.<span class="font_28">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlTotalPrices.value = result.total;
|
||||
}
|
||||
totalPrices.value = result.price;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 支付
|
||||
const payment = () => {
|
||||
let data = {
|
||||
num: orderData.value.spuNum * 1,
|
||||
remark: remark.value,
|
||||
total_number: totalNumber.value,
|
||||
spu_id: orderData.value.id * 1,
|
||||
sku_id: orderData.value.skuId * 1,
|
||||
ship: receivingIndex.value == 0 ? 1 : 2,
|
||||
name: receivingIndex.value == 0 ? userDetail.value.name : address.value.userName,
|
||||
mobile: receivingIndex.value == 0 ? userDetail.value.mobile : address.value.telNumber,
|
||||
address: receivingIndex.value == 0 ? '广东省深圳市南山区南新路阳光科创中心B座33楼3301(荔林地铁站C口步行170米)' : detailedAddress.value,
|
||||
pay_type: 1,
|
||||
};
|
||||
if (receivingIndex.value == 1) {
|
||||
if (!detailedAddress.value) {
|
||||
showToast('请填写收货地址');
|
||||
return;
|
||||
}
|
||||
if (!address.value.userName) {
|
||||
showToast('请填写你的姓名');
|
||||
return;
|
||||
}
|
||||
if (!address.value.telNumber) {
|
||||
showToast('请填写你的手机号');
|
||||
return;
|
||||
}
|
||||
if (!/^1(3|4|5|6|7|8|9)\d{9}$/.test(address.value.telNumber)) {
|
||||
showToast('请输入正确的手机号码');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// let newData = JSON.stringify(window.webAppInterface);
|
||||
// alert(newData);
|
||||
// let trade_no = 's2common_1723261299061930';
|
||||
// window.location.href = `myapp://data?data=${trade_no}`;
|
||||
if (throttle.value) {
|
||||
throttle.value = false;
|
||||
requestGo({ url: `app/v2/shop/common/buy`, data, method: 'post' })
|
||||
.then((res) => {
|
||||
if (res.code == 7) {
|
||||
showDialog({
|
||||
title: '温馨提示',
|
||||
message: '价格已经发生变化,请重新确认',
|
||||
}).then(() => {
|
||||
throttle.value = true;
|
||||
prepay();
|
||||
});
|
||||
return;
|
||||
}
|
||||
throttle.value = true;
|
||||
let result = JSON.stringify(res.data);
|
||||
|
||||
if (isIOS.value) {
|
||||
//调用iOS app方法
|
||||
window.webkit.messageHandlers.ImmediatePayment.postMessage(result);
|
||||
} else {
|
||||
// 调用安卓 app方法
|
||||
window.location.href = `myapp://data?data=${result}`;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
throttle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取最后一次物流地址信息
|
||||
const getMailData = () => {
|
||||
if (localStorage.getItem('logsiticsAddress')) {
|
||||
let result = JSON.parse(localStorage.getItem('logsiticsAddress'));
|
||||
console.log(result, '===');
|
||||
address.value.userName = result.name; // 收货人姓名
|
||||
address.value.telNumber = result.mobile; // 收货人手机号码
|
||||
detailedAddress.value = `${result.province}` + `${result.city}` + `${result.county}` + `${result.detail_address}`;
|
||||
} else {
|
||||
requestGo({ url: `/app/v2/shop/common/order/express/last`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
if (result && result.mobile) {
|
||||
detailedAddress.value = result.address;
|
||||
address.value.userName = result.name;
|
||||
address.value.telNumber = result.mobile;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const callBack = () => {
|
||||
requestGo({ url: `app/v2/shop/common/wechatpay/callback/${tradeNo.value}`, hideLoading: true, method: 'post' })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
closeToast();
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取微信收货地址
|
||||
const openWx = () => {
|
||||
if (remark.value) {
|
||||
let setRemark = JSON.stringify({ id: orderData.value.id, remark: remark.value });
|
||||
localStorage.setItem('setRemark', setRemark);
|
||||
}
|
||||
router.push({
|
||||
name: 'appMyAddress',
|
||||
});
|
||||
// if (receivingIndex.value == 0) {
|
||||
// return;
|
||||
// }
|
||||
// wx.openAddress({
|
||||
// success(res) {
|
||||
// address.value.userName = res.userName; // 收货人姓名
|
||||
// address.value.postalCode = res.postalCode; // 邮编
|
||||
// address.value.provinceName = res.provinceName; // 国标收货地址第一级地址(省)
|
||||
// address.value.cityName = res.cityName; // 国标收货地址第二级地址(市)
|
||||
// address.value.countryName = res.countryName; // 国标收货地址第三级地址(国家)
|
||||
// address.value.detailInfo = res.detailInfo; // 详细收货地址信息
|
||||
// address.value.nationalCode = res.nationalCode; // 收货地址国家码
|
||||
// address.value.telNumber = res.telNumber; // 收货人手机号码
|
||||
// detailedAddress.value = `${res.provinceName}` + `${res.cityName}` + `${res.countryName}` + `${res.detailInfo}`;
|
||||
// },
|
||||
// });
|
||||
};
|
||||
|
||||
// 选择收货方式
|
||||
const selectSymptom = (index) => {
|
||||
receivingIndex.value = index;
|
||||
prepay();
|
||||
};
|
||||
const userDetail = ref({
|
||||
name: '',
|
||||
mobile: '',
|
||||
});
|
||||
const getUserDetail = () => {
|
||||
request({ url: `/app/get/user/info`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
|
||||
userDetail.value.name = result.name;
|
||||
userDetail.value.mobile = result.mobile;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query;
|
||||
orderData.value = JSON.parse(route.orderData as any);
|
||||
console.log(router.currentRoute.value, 'router.currentRoute.value===');
|
||||
getUserDetail();
|
||||
prepay();
|
||||
getMailData();
|
||||
getDetail();
|
||||
let ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1 || ua.indexOf('android') != -1) {
|
||||
isIOS.value = false;
|
||||
} else {
|
||||
isIOS.value = true;
|
||||
}
|
||||
console.log(isIOS.value, 'isIOS.value==');
|
||||
if (localStorage.getItem('setRemark')) {
|
||||
let setRemark = JSON.parse(localStorage.getItem('setRemark'));
|
||||
if (orderData.value.id == setRemark.id) remark.value = setRemark.remark;
|
||||
localStorage.removeItem('setRemark');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-shopOrderConfirm {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-m-inf {
|
||||
padding: px2rem(30);
|
||||
|
||||
.ui-receiving-item {
|
||||
width: 50%;
|
||||
height: px2rem(88);
|
||||
margin-top: px2rem(-6);
|
||||
|
||||
.ui-receiving-text {
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
white-space: nowrap;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-receiving-icon,
|
||||
.ui-receiving-icon-v2 {
|
||||
width: 100%;
|
||||
height: px2rem(88);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ui-receiving-icon-v2 {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-address-box {
|
||||
padding: px2rem(24) px2rem(24) px2rem(12) px2rem(24);
|
||||
margin-bottom: px2rem(24);
|
||||
background: #ffffff;
|
||||
border-radius: 0 0 px2rem(16) px2rem(16);
|
||||
position: relative;
|
||||
|
||||
.ui-address-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-address-title-box {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
||||
.ui-address-title {
|
||||
width: px2rem(132);
|
||||
text-align: justify;
|
||||
text-align-last: justify;
|
||||
}
|
||||
|
||||
.ui-address-content {
|
||||
width: px2rem(440);
|
||||
max-width: px2rem(440);
|
||||
margin-left: px2rem(20);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-address-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
margin-top: px2rem(4);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-decoration-icon {
|
||||
width: px2rem(664);
|
||||
height: px2rem(4);
|
||||
position: absolute;
|
||||
bottom: px2rem(2);
|
||||
left: px2rem(14);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-inf-box,
|
||||
.ui-remark-box {
|
||||
padding: px2rem(24);
|
||||
margin-bottom: px2rem(20);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-m-avt-lst {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.ui-pic {
|
||||
width: px2rem(160);
|
||||
height: px2rem(160);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
display: block;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-m-lst-ri {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-title {
|
||||
max-width: px2rem(462);
|
||||
line-height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-product-spu-name {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.ui-product-num {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-total-price {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: px2rem(6);
|
||||
|
||||
.ui-total-original-price {
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-discounts-box {
|
||||
padding-top: px2rem(20);
|
||||
border-top: px2rem(2) solid #eaeaea;
|
||||
margin-top: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-buy-num-box {
|
||||
padding: 0 px2rem(22);
|
||||
height: px2rem(56);
|
||||
background: #f7f7f7;
|
||||
border-radius: px2rem(8);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-remark-box {
|
||||
.ui-remark-text {
|
||||
max-width: px2rem(400);
|
||||
}
|
||||
|
||||
.ui-remark-triangle-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-price {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-buy-price-symbol {
|
||||
margin-right: px2rem(4);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-operation-box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
padding: px2rem(16) px2rem(24) px2rem(50) px2rem(30);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-buy-btn {
|
||||
width: px2rem(400);
|
||||
height: px2rem(88);
|
||||
border-radius: px2rem(44);
|
||||
background: linear-gradient(151deg, #18ca6e 0%, #0aa555 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-remark-input-box {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding: px2rem(30) px2rem(30) px2rem(60) px2rem(30);
|
||||
border-radius: px2rem(24);
|
||||
|
||||
.ui-close-icon {
|
||||
position: absolute;
|
||||
right: px2rem(24);
|
||||
top: px2rem(24);
|
||||
z-index: 22;
|
||||
width: px2rem(48);
|
||||
height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-remark-input {
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin: px2rem(40) 0 px2rem(24) 0;
|
||||
}
|
||||
|
||||
.ui-remark-btn {
|
||||
width: 100%;
|
||||
height: px2rem(88);
|
||||
border-radius: px2rem(8);
|
||||
background: linear-gradient(151deg, #18ca6e 0%, #0aa555 100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
32
src/views/appDir/longPicture.vue
Normal file
32
src/views/appDir/longPicture.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="ui-longPicture">
|
||||
<img class="ui-pic" :src="imgUrl" alt="" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import router from '@/router';
|
||||
|
||||
defineOptions({ name: 'LongPicture' });
|
||||
|
||||
const imgUrl = ref<any>('https://image.fulllinkai.com/202408/30/978ba8c872b24be1558afd845cd0b606.jpeg');
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query;
|
||||
if (route.imgUrl) {
|
||||
imgUrl.value = route.imgUrl;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-longPicture {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-pic {
|
||||
width: 100vw;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
633
src/views/appDir/miniShopOrderConfirm.vue
Normal file
633
src/views/appDir/miniShopOrderConfirm.vue
Normal file
@ -0,0 +1,633 @@
|
||||
<template>
|
||||
<div v-if="loading" class="ui-shopOrderConfirm">
|
||||
<div class="ui-m-inf">
|
||||
<div class="ui-relative">
|
||||
<div class="f-fbc">
|
||||
<div v-for="(item, index) in receivingList" :key="index" class="font_28 f-fcc ui-receiving-item" :class="receivingIndex == index ? 'colorAppGreen font_30 bold' : 'color3'" @click="selectSymptom(index)">
|
||||
<div class="ui-receiving-text">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img v-show="receivingIndex == 0" class="ui-receiving-icon" src="https://image.fulllinkai.com/202404/09/122fe1183af7e8e15dfa3ea4b5ba861f.png" alt="" @click="selectSymptom(1)" />
|
||||
<img v-show="receivingIndex == 1" class="ui-receiving-icon-v2" src="https://image.fulllinkai.com/202404/09/64e3443b623f73dd341389fc53e303e8.png" alt="" @click="selectSymptom(0)" />
|
||||
</div>
|
||||
<div class="ui-address-box">
|
||||
<div v-if="receivingIndex == 0">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">自提地址:</div>
|
||||
<div class="font_28 color3 ui-address-content">广东省深圳市南山区南新路阳光科创中心B座33楼3301(荔林地铁站C口步行170米)</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/3b4a522e6bdb081a14186712f87cb20b.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">联系人:</div>
|
||||
<div class="font_28 color3 ui-address-content">友福客服,17788799376</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else @click="openWx">
|
||||
<div v-if="detailedAddress">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">收货地址:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ detailedAddress }}</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/3b4a522e6bdb081a14186712f87cb20b.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">收货人:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ address.userName }},{{ address.telNumber }}</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="ui-address-item ui-pt-6 ui-pb-32">
|
||||
<div class="font_28 color3 bold">点击添加收货地址</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <img class="ui-decoration-icon" src="https://image.fulllinkai.com/202309/20/e8a30e7308236eb3894fec737b66657d.png" alt="" />-->
|
||||
</div>
|
||||
<div v-if="receivingIndex == 0" class="ui-remark-box ui-address-box font_28">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">自提人:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ userDetail.name }},{{ userDetail.mobile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-inf-box">
|
||||
<div class="ui-m-avt-lst ui-relative">
|
||||
<img class="ui-pic" :src="icon" alt="" />
|
||||
<div class="ui-m-lst-ri">
|
||||
<div class="font_32 ellipsis_2 bold ui-title">{{ title }}</div>
|
||||
<div class="font_28 ui-product-spu-name color6">已选:{{ orderData.spuName }}{{ orderData.spuSubName ? ';' + orderData.spuSubName : '' }}</div>
|
||||
<div class="font_28 color3 ui-product-num">X {{ orderData.spuNum }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-mt-40">
|
||||
<div class="font_28 color3">商品总额</div>
|
||||
<div class="font_28 bold"><span class="ui-buy-price-symbol">¥</span>{{ totalPrices }}</div>
|
||||
</div>
|
||||
<div v-if="receivingIndex != 0" class="f-fbc ui-mt-20">
|
||||
<div class="font_28 color3">快递费用</div>
|
||||
<div class="font_28"><span class="ui-buy-price-symbol">¥</span>{{ freightPrice }}</div>
|
||||
</div>
|
||||
<!-- <div v-if="related.share_user_name || related.invite_user_name || related.referrer_user_name">-->
|
||||
<!-- <div v-if="related.share_user_name" class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">分享用户</div>-->
|
||||
<!-- <div class="font_28 bold color6">{{ related.share_user_name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="related.invite_user_name" class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">邀请用户</div>-->
|
||||
<!-- <div class="font_28 bold color6">{{ related.invite_user_name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="related.referrer_user_name" class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">推荐用户</div>-->
|
||||
<!-- <div class="font_28 bold color6">{{ related.referrer_user_name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-else>-->
|
||||
<!-- <div class="f-fbc ui-mt-22">-->
|
||||
<!-- <div class="font_28 color3">关联信息</div>-->
|
||||
<!-- <div class="font_28 bold color6">暂无关联信息</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="f-fbc ui-mt-20">-->
|
||||
<!-- <div class="font_28 color3">服务</div>-->
|
||||
<!-- <div class="font_28">七天无理由退货</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="ui-discounts-box f-fbc">
|
||||
<div></div>
|
||||
<div class="f-fcr">
|
||||
<div class="font_28 color3">应付金额:</div>
|
||||
<div class="f-fcl ui-buy-price">
|
||||
<span class="font_28 ui-buy-price-symbol bold">¥</span>
|
||||
<div class="font_32 bold"><span v-html="htmlTotalPrices"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-remark-box font_28 f-fbc" @click="showRemark = true">
|
||||
<div class="color3">订单备注</div>
|
||||
<div class="ui-remark-text">
|
||||
<div class="f-fcr text-right">
|
||||
<div class="ui-mr-10 ellipsis_1" :class="remark ? 'color3' : 'color6'">{{ remark ? remark : '请填写备注' }}</div>
|
||||
<img class="ui-remark-triangle-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-operation-box f-fbc">
|
||||
<div class="font_24 color3 f-fcl">
|
||||
合计:
|
||||
<div class="f-fcl ui-buy-price">
|
||||
<span class="font_28 ui-buy-price-symbol bold">¥</span>
|
||||
<div class="font_44 bold"><span v-html="htmlTotalPrices"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-buy-btn f-fcc colorF font_30 bold" @click="payment">确认支付</div>
|
||||
</div>
|
||||
<van-popup v-model:show="showRemark" round position="bottom" :duration="0.5">
|
||||
<div class="ui-remark-input-box">
|
||||
<img class="ui-close-icon" src="https://image.fulllinkai.com/202405/16/20161b3e74af1eacd328181ff40b0358.png" alt="" @click="(showRemark = false), (remark = '')" />
|
||||
<div class="text-center color3 font_32 bold">订单备注</div>
|
||||
<van-field v-model="remark" type="textarea" autosize rows="5" show-word-limit class="ui-remark-input f-fcc font_40 color3 bold" :maxlength="200" placeholder="请填写备注" />
|
||||
<div class="font_32 colorF f-fcc ui-remark-btn" @click="showRemark = false">确认</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { closeToast, showToast, showDialog } from 'vant';
|
||||
import wx from 'weixin-js-sdk';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestApp';
|
||||
import request from '@/utils/requestAppPHP';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
defineOptions({ name: 'ShopOrderConfirm' });
|
||||
const isIOS = ref<any>(null);
|
||||
const userStore = useUserStore() as any;
|
||||
const throttle = ref(true);
|
||||
const orderData = ref<any>({});
|
||||
const loading = ref<any>(false);
|
||||
const timer = ref<any>(null);
|
||||
|
||||
const receivingIndex = ref(1);
|
||||
const receivingList = ref<any[]>(['线下自提', '物流配送']);
|
||||
|
||||
const related = ref<any>({}); // 关联分享、推荐、介绍用户信息
|
||||
const title = ref<any>('');
|
||||
const icon = ref<any>('');
|
||||
const showRemark = ref(false);
|
||||
const remark = ref<any>('');
|
||||
|
||||
const totalPrices = ref<any>(0); // 合计价格
|
||||
const htmlTotalPrices = ref<any>(0); // 合计价格小数点字号
|
||||
const freightPrice = ref<any>(0); // 邮费
|
||||
const totalNumber = ref<any>(0);
|
||||
|
||||
const wxPay = ref<any>(null); // 支付所需config
|
||||
const tradeId = ref<any>(''); // 订单ID
|
||||
const tradeNo = ref<any>(''); // 订单号
|
||||
|
||||
const detailedAddress = ref<any>('');
|
||||
const address = ref<any>({
|
||||
userName: '',
|
||||
postalCode: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
countyName: '',
|
||||
detailInfo: '',
|
||||
nationalCode: '',
|
||||
telNumber: '',
|
||||
});
|
||||
|
||||
// 获取商品详情
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/app/v2/shop/common/spu/detail/${orderData.value.id}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
title.value = result.spu.title;
|
||||
icon.value = result.spu.icon;
|
||||
related.value = result.related_person_detail;
|
||||
// 获取上一次记录的物流配送地址
|
||||
if (result.recive && result.recive.address) {
|
||||
address.value.userName = result.recive.name;
|
||||
address.value.telNumber = result.recive.mobile;
|
||||
detailedAddress.value = result.recive.address;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取预计算价格
|
||||
const prepay = () => {
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => {
|
||||
requestGo({ url: `/app/v2/shop/common/sku/prepay/${orderData.value.skuId}/${orderData.value.spuNum}/${receivingIndex.value == 0 ? 1 : 2}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
freightPrice.value = result.freight;
|
||||
totalNumber.value = result.total_number;
|
||||
loading.value = true;
|
||||
// 小数点后面字号变小
|
||||
if (`${result.total}`.includes('.')) {
|
||||
let splitPrice = result.total.split('.');
|
||||
htmlTotalPrices.value = `${splitPrice[0]}.<span class="font_28">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlTotalPrices.value = result.total;
|
||||
}
|
||||
totalPrices.value = result.price;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 支付
|
||||
const payment = () => {
|
||||
let data = {
|
||||
num: orderData.value.spuNum * 1,
|
||||
remark: remark.value,
|
||||
total_number: totalNumber.value,
|
||||
spu_id: orderData.value.id * 1,
|
||||
sku_id: orderData.value.skuId * 1,
|
||||
ship: receivingIndex.value == 0 ? 1 : 2,
|
||||
name: receivingIndex.value == 0 ? userDetail.value.name : address.value.userName,
|
||||
mobile: receivingIndex.value == 0 ? userDetail.value.mobile : address.value.telNumber,
|
||||
address: receivingIndex.value == 0 ? '广东省深圳市南山区南新路阳光科创中心B座33楼3301(荔林地铁站C口步行170米)' : detailedAddress.value,
|
||||
pay_type: 1,
|
||||
};
|
||||
if (receivingIndex.value == 1) {
|
||||
if (!detailedAddress.value) {
|
||||
showToast('请填写收货地址');
|
||||
return;
|
||||
}
|
||||
if (!address.value.userName) {
|
||||
showToast('请填写你的姓名');
|
||||
return;
|
||||
}
|
||||
if (!address.value.telNumber) {
|
||||
showToast('请填写你的手机号');
|
||||
return;
|
||||
}
|
||||
if (!/^1(3|4|5|6|7|8|9)\d{9}$/.test(address.value.telNumber)) {
|
||||
showToast('请输入正确的手机号码');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// let newData = JSON.stringify(window.webAppInterface);
|
||||
// alert(newData);
|
||||
// let trade_no = 's2common_1723261299061930';
|
||||
// window.location.href = `myapp://data?data=${trade_no}`;
|
||||
if (throttle.value) {
|
||||
throttle.value = false;
|
||||
requestGo({ url: `app/v2/shop/common/buy`, data, method: 'post' })
|
||||
.then((res) => {
|
||||
if (res.code == 7) {
|
||||
showDialog({
|
||||
title: '温馨提示',
|
||||
message: '价格已经发生变化,请重新确认',
|
||||
}).then(() => {
|
||||
throttle.value = true;
|
||||
prepay();
|
||||
});
|
||||
return;
|
||||
}
|
||||
throttle.value = true;
|
||||
let result = JSON.stringify(res.data);
|
||||
|
||||
if (isIOS.value) {
|
||||
//调用iOS app方法
|
||||
window.webkit.messageHandlers.ImmediatePayment.postMessage(result);
|
||||
} else {
|
||||
// 调用安卓 app方法
|
||||
window.location.href = `myapp://data?data=${result}`;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
throttle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取最后一次物流地址信息
|
||||
const getMailData = () => {
|
||||
if (localStorage.getItem('logsiticsAddress')) {
|
||||
let result = JSON.parse(localStorage.getItem('logsiticsAddress'));
|
||||
console.log(result, '===');
|
||||
address.value.userName = result.name; // 收货人姓名
|
||||
address.value.telNumber = result.mobile; // 收货人手机号码
|
||||
detailedAddress.value = `${result.province}` + `${result.city}` + `${result.county}` + `${result.detail_address}`;
|
||||
} else {
|
||||
requestGo({ url: `/app/v2/shop/common/order/express/last`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
if (result && result.mobile) {
|
||||
detailedAddress.value = result.address;
|
||||
address.value.userName = result.name;
|
||||
address.value.telNumber = result.mobile;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const callBack = () => {
|
||||
requestGo({ url: `app/v2/shop/common/wechatpay/callback/${tradeNo.value}`, hideLoading: true, method: 'post' })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
closeToast();
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取微信收货地址
|
||||
const openWx = () => {
|
||||
if (remark.value) {
|
||||
let setRemark = JSON.stringify({ id: orderData.value.id, remark: remark.value });
|
||||
localStorage.setItem('setRemark', setRemark);
|
||||
}
|
||||
router.push({
|
||||
name: 'appMyAddress',
|
||||
});
|
||||
// if (receivingIndex.value == 0) {
|
||||
// return;
|
||||
// }
|
||||
// wx.openAddress({
|
||||
// success(res) {
|
||||
// address.value.userName = res.userName; // 收货人姓名
|
||||
// address.value.postalCode = res.postalCode; // 邮编
|
||||
// address.value.provinceName = res.provinceName; // 国标收货地址第一级地址(省)
|
||||
// address.value.cityName = res.cityName; // 国标收货地址第二级地址(市)
|
||||
// address.value.countryName = res.countryName; // 国标收货地址第三级地址(国家)
|
||||
// address.value.detailInfo = res.detailInfo; // 详细收货地址信息
|
||||
// address.value.nationalCode = res.nationalCode; // 收货地址国家码
|
||||
// address.value.telNumber = res.telNumber; // 收货人手机号码
|
||||
// detailedAddress.value = `${res.provinceName}` + `${res.cityName}` + `${res.countryName}` + `${res.detailInfo}`;
|
||||
// },
|
||||
// });
|
||||
};
|
||||
|
||||
// 选择收货方式
|
||||
const selectSymptom = (index) => {
|
||||
receivingIndex.value = index;
|
||||
prepay();
|
||||
};
|
||||
const userDetail = ref({
|
||||
name: '',
|
||||
mobile: '',
|
||||
});
|
||||
const getUserDetail = () => {
|
||||
request({ url: `/app/get/user/info`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
|
||||
userDetail.value.name = result.name;
|
||||
userDetail.value.mobile = result.mobile;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query;
|
||||
orderData.value = JSON.parse(route.orderData as any);
|
||||
console.log(router.currentRoute.value, 'router.currentRoute.value===');
|
||||
getUserDetail();
|
||||
prepay();
|
||||
getMailData();
|
||||
getDetail();
|
||||
let ua = navigator.userAgent.toLowerCase();
|
||||
if (ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1 || ua.indexOf('android') != -1) {
|
||||
isIOS.value = false;
|
||||
} else {
|
||||
isIOS.value = true;
|
||||
}
|
||||
console.log(isIOS.value, 'isIOS.value==');
|
||||
if (localStorage.getItem('setRemark')) {
|
||||
let setRemark = JSON.parse(localStorage.getItem('setRemark'));
|
||||
if (orderData.value.id == setRemark.id) remark.value = setRemark.remark;
|
||||
localStorage.removeItem('setRemark');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-shopOrderConfirm {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-m-inf {
|
||||
padding: px2rem(30);
|
||||
|
||||
.ui-receiving-item {
|
||||
width: 50%;
|
||||
height: px2rem(88);
|
||||
margin-top: px2rem(-6);
|
||||
|
||||
.ui-receiving-text {
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
white-space: nowrap;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-receiving-icon,
|
||||
.ui-receiving-icon-v2 {
|
||||
width: 100%;
|
||||
height: px2rem(88);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ui-receiving-icon-v2 {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-address-box {
|
||||
padding: px2rem(24) px2rem(24) px2rem(12) px2rem(24);
|
||||
margin-bottom: px2rem(24);
|
||||
background: #ffffff;
|
||||
border-radius: 0 0 px2rem(16) px2rem(16);
|
||||
position: relative;
|
||||
|
||||
.ui-address-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-address-title-box {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
||||
.ui-address-title {
|
||||
width: px2rem(132);
|
||||
text-align: justify;
|
||||
text-align-last: justify;
|
||||
}
|
||||
|
||||
.ui-address-content {
|
||||
width: px2rem(440);
|
||||
max-width: px2rem(440);
|
||||
margin-left: px2rem(20);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-address-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
margin-top: px2rem(4);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-decoration-icon {
|
||||
width: px2rem(664);
|
||||
height: px2rem(4);
|
||||
position: absolute;
|
||||
bottom: px2rem(2);
|
||||
left: px2rem(14);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-inf-box,
|
||||
.ui-remark-box {
|
||||
padding: px2rem(24);
|
||||
margin-bottom: px2rem(20);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-m-avt-lst {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.ui-pic {
|
||||
width: px2rem(160);
|
||||
height: px2rem(160);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
display: block;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-m-lst-ri {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-title {
|
||||
max-width: px2rem(462);
|
||||
line-height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-product-spu-name {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.ui-product-num {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-total-price {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: px2rem(6);
|
||||
|
||||
.ui-total-original-price {
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-discounts-box {
|
||||
padding-top: px2rem(20);
|
||||
border-top: px2rem(2) solid #eaeaea;
|
||||
margin-top: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-buy-num-box {
|
||||
padding: 0 px2rem(22);
|
||||
height: px2rem(56);
|
||||
background: #f7f7f7;
|
||||
border-radius: px2rem(8);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-remark-box {
|
||||
.ui-remark-text {
|
||||
max-width: px2rem(400);
|
||||
}
|
||||
|
||||
.ui-remark-triangle-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-price {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-buy-price-symbol {
|
||||
margin-right: px2rem(4);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-operation-box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
padding: px2rem(16) px2rem(24) px2rem(50) px2rem(30);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-buy-btn {
|
||||
width: px2rem(400);
|
||||
height: px2rem(88);
|
||||
border-radius: px2rem(44);
|
||||
background: linear-gradient(151deg, #18ca6e 0%, #0aa555 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-remark-input-box {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding: px2rem(30) px2rem(30) px2rem(60) px2rem(30);
|
||||
border-radius: px2rem(24);
|
||||
|
||||
.ui-close-icon {
|
||||
position: absolute;
|
||||
right: px2rem(24);
|
||||
top: px2rem(24);
|
||||
z-index: 22;
|
||||
width: px2rem(48);
|
||||
height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-remark-input {
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin: px2rem(40) 0 px2rem(24) 0;
|
||||
}
|
||||
|
||||
.ui-remark-btn {
|
||||
width: 100%;
|
||||
height: px2rem(88);
|
||||
border-radius: px2rem(8);
|
||||
background: linear-gradient(151deg, #18ca6e 0%, #0aa555 100%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
58
src/views/errorDir/accessDenied.vue
Normal file
58
src/views/errorDir/accessDenied.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<div class="ui-accessDenied">
|
||||
<div class="ui-container">
|
||||
<img class="ui-service-icon" src="https://image.fulllinkai.com/202312/28/93493e89f7196fa765f4587c9e28ed0d.jpeg" alt="" />
|
||||
<div class="font_28 color6 text-center ui-tips" @click.stop="jumpPath">对不起,您还没有当前操作的权限,长按识别二维码联系客服</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import router from '@/router';
|
||||
|
||||
defineOptions({ name: 'AccessDenied' });
|
||||
|
||||
const id = ref<any>('');
|
||||
|
||||
const jumpPath = () => {
|
||||
router.replace({
|
||||
name: 'partnerInfo',
|
||||
});
|
||||
router.go(-1);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query;
|
||||
id.value = route.id;
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-accessDenied {
|
||||
background: #ffffff;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-container {
|
||||
position: absolute;
|
||||
top: 20vh;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
.ui-service-icon {
|
||||
width: px2rem(640);
|
||||
height: px2rem(640);
|
||||
display: block;
|
||||
margin: px2rem(-100) auto px2rem(-70) auto;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.ui-tips {
|
||||
position: relative;
|
||||
z-index: 22;
|
||||
padding: 0 px2rem(86);
|
||||
line-height: px2rem(48);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
22
src/views/errorDir/notFound.vue
Normal file
22
src/views/errorDir/notFound.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="ui-notFound">
|
||||
<div class="">
|
||||
<img class="" src="https://image.fulllinkai.com/202108/19/7067c44ad027325039f5c75fc92176d0.png" alt="" />
|
||||
<div class="font_30 color9 text-center">页面已删除</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
defineOptions({ name: 'NotFound' });
|
||||
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-notFound {
|
||||
background: #ffffff;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
658
src/views/subDir/appUserLogin.vue
Normal file
658
src/views/subDir/appUserLogin.vue
Normal file
@ -0,0 +1,658 @@
|
||||
<template>
|
||||
<div class="ui-appDownloadPageV2">
|
||||
<!-- <div style="position: relative; top: 0; z-index: 999">-->
|
||||
<!-- <div class="appWatchBox">-->
|
||||
<!-- <van-image v-if="isWechatDevice" class="appWatchTop-pic" src="https://images.health.ufutx.com/202406/12/d96d8221ef6070f547723282b5b3923f.jpeg" />-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<img class="ui-top-logo" src="https://image.fulllinkai.com/202408/24/15e99ac9778827d49d39d50b6361b08e.png" alt="" />
|
||||
<div class="ui-data-box">
|
||||
<!-- ----->
|
||||
<van-tabs v-model:active="active">
|
||||
<!-- <van-tab title="">-->
|
||||
<div class="mobile ui-mt-60">
|
||||
<div class="f-fcl ui-relative">
|
||||
<!-- <div class="font_32 color76 ui-title">手机号</div>-->
|
||||
<!-- <div class="f-fcl ui-area-code" @click.stop="showChooseArea = !showChooseArea">-->
|
||||
<!-- <div class="font_30 color3">{{ AreaValue }}</div>-->
|
||||
<!-- <img v-if="showChooseArea" class="Angle_icon" src="https://image.fulllinkai.com/202405/17/f2d6c2fcda5d4a01fb28fe4a894d7f7a.png" alt="" />-->
|
||||
<!-- <img v-else class="Angle_icon" src="https://image.fulllinkai.com/202405/17/fb15a98cfa7c515075a5a4f9d7c3e589.png" alt="" />-->
|
||||
<!-- </div>-->
|
||||
<!-- <van-search v-model="mobile" clear-icon="https://image.fulllinkai.com/202408/24/ef7ecf7fe24f4d5cafce2b54d82f86fc.png" class="ui-user-input font_32 color3" left-icon="" clear-trigger="always" placeholder="请输入手机号" />-->
|
||||
<van-field v-model="mobile" type="number" class="ui-user-input font_32 color3" placeholder="请输入手机号" />
|
||||
<div v-if="showChooseArea" class="ui-relative area_code_choose_box">
|
||||
<div class="area_code_choose_list">
|
||||
<div v-for="(item, index) in areaList" :key="index" class="alignment area_code_choose" @click="selectedArea(item, index)">
|
||||
<div class="font_32 color3 area_code_choose_item" :class="AreaIndex == index ? 'colorPrice' : ''"> {{ item.area_code }} {{ item.label }} </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showChooseArea" class="ui-area-mask" @click="showChooseArea = false"></div>
|
||||
</div>
|
||||
<div class="ui-line"></div>
|
||||
<div class="f-fbc">
|
||||
<div class="f-fcl">
|
||||
<!-- <div class="font_32 color76 ui-title">验证码</div>-->
|
||||
<!-- <van-search v-model="code" clear-icon="https://image.fulllinkai.com/202408/24/ef7ecf7fe24f4d5cafce2b54d82f86fc.png" class="ui-user-input-v2 font_32 color3" left-icon="" clear-trigger="always" placeholder="请输入验证码" />-->
|
||||
<van-field v-model="code" type="number" maxlength="6" class="ui-user-input font_32 color3" placeholder="请输入验证码" />
|
||||
</div>
|
||||
<div class="ui-code-btn font_28 f-fcc" :class="time == 60 ? 'colorF' : 'set colorBussnessTheme'" @click="getCode">{{ time == 60 ? '获取验证码' : `${time}s` }} </div>
|
||||
</div>
|
||||
|
||||
<div class="ui-line-v2"></div>
|
||||
<!-- <div class="f-fcl ui-relative">-->
|
||||
<!-- <!– <div class="font_32 color76 ui-title">密码</div>–>-->
|
||||
<!-- <!– <van-search v-model="mobile" clear-icon="https://image.fulllinkai.com/202408/24/ef7ecf7fe24f4d5cafce2b54d82f86fc.png" class="ui-user-input font_32 color3" left-icon="" clear-trigger="always" placeholder="请输入手机号" />–>-->
|
||||
<!-- <van-field v-model="pwd" type="number" class="ui-user-input font_32 color3" placeholder="请输入密码" />-->
|
||||
<!-- <div v-if="showChooseArea" class="ui-area-mask" @click="showChooseArea = false"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="ui-line-v2"></div>-->
|
||||
<div class="font_26" style="color: #b2b3b5">注:{{ areaList[AreaIndex].tips }}</div>
|
||||
</div>
|
||||
<!-- </van-tab>-->
|
||||
<!-- <van-tab title="密码登录">-->
|
||||
<!-- <div class="mobile ui-mt-60">-->
|
||||
<!-- <div class="f-fcl ui-relative">-->
|
||||
<!-- <!– <div class="font_32 color76 ui-title">手机号</div>–>-->
|
||||
<!-- <!– <div class="f-fcl ui-area-code" @click.stop="showChooseArea = !showChooseArea">–>-->
|
||||
<!-- <!– <div class="font_30 color3">{{ AreaValue }}</div>–>-->
|
||||
<!-- <!– <img v-if="showChooseArea" class="Angle_icon" src="https://image.fulllinkai.com/202405/17/f2d6c2fcda5d4a01fb28fe4a894d7f7a.png" alt="" />–>-->
|
||||
<!-- <!– <img v-else class="Angle_icon" src="https://image.fulllinkai.com/202405/17/fb15a98cfa7c515075a5a4f9d7c3e589.png" alt="" />–>-->
|
||||
<!-- <!– </div>–>-->
|
||||
<!-- <!– <van-search v-model="mobile" clear-icon="https://image.fulllinkai.com/202408/24/ef7ecf7fe24f4d5cafce2b54d82f86fc.png" class="ui-user-input font_32 color3" left-icon="" clear-trigger="always" placeholder="请输入手机号" />–>-->
|
||||
<!-- <van-field v-model="mobile" type="number" class="ui-user-input font_32 color3" placeholder="请输入手机号" />-->
|
||||
<!-- <div v-if="showChooseArea" class="ui-relative area_code_choose_box">-->
|
||||
<!-- <div class="area_code_choose_list">-->
|
||||
<!-- <div v-for="(item, index) in areaList" :key="index" class="alignment area_code_choose" @click="selectedArea(item, index)">-->
|
||||
<!-- <div class="font_32 color3 area_code_choose_item" :class="AreaIndex == index ? 'colorPrice' : ''"> {{ item.area_code }} {{ item.label }} </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="showChooseArea" class="ui-area-mask" @click="showChooseArea = false"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <!– <van-search v-model="mobile" clear-icon="https://image.fulllinkai.com/202408/24/ef7ecf7fe24f4d5cafce2b54d82f86fc.png" class="ui-user-input font_32 color3" left-icon="" clear-trigger="always" placeholder="请输入手机号" />–>-->
|
||||
<!-- <!– <van-field v-model="mobile" type="number" class="ui-user-input font_32 color3" placeholder="请输入手机号" />–>-->
|
||||
<!-- <div v-if="showChooseArea" class="ui-relative area_code_choose_box">-->
|
||||
<!-- <div class="area_code_choose_list">-->
|
||||
<!-- <div v-for="(item, index) in areaList" :key="index" class="alignment area_code_choose" @click="selectedArea(item, index)">-->
|
||||
<!-- <div class="font_32 color3 area_code_choose_item" :class="AreaIndex == index ? 'colorPrice' : ''"> {{ item.area_code }} {{ item.label }} </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- - -->
|
||||
<!-- </div>-->
|
||||
<!-- <div v-if="showChooseArea" class="ui-area-mask" @click="showChooseArea = false"></div>-->
|
||||
<!-- <div class="ui-line"></div>-->
|
||||
<!-- <!– <div class="f-fbc">–>-->
|
||||
<!-- <!– <div class="f-fcl">–>-->
|
||||
<!-- <!– <van-field v-model="emailCode" type="number" maxlength="6" class="ui-user-input font_32 color3" placeholder="请输入验证码" />–>-->
|
||||
<!-- <!– </div>–>-->
|
||||
<!-- <!– <div class="ui-code-btn font_28 f-fcc" :class="timeV2 == 60 ? 'colorF' : 'set colorBussnessTheme'" @click="getEmailCode">{{ timeV2 == 60 ? '获取验证码' : `${timeV2}s` }} </div>–>-->
|
||||
<!-- <!– </div>–>-->
|
||||
|
||||
<!-- <!– <div class="ui-line-v2"></div>–>-->
|
||||
<!-- <div class="f-fcl ui-relative">-->
|
||||
<!-- <!– <div class="font_32 color76 ui-title">密码</div>–>-->
|
||||
<!-- <!– <van-search v-model="mobile" clear-icon="https://image.fulllinkai.com/202408/24/ef7ecf7fe24f4d5cafce2b54d82f86fc.png" class="ui-user-input font_32 color3" left-icon="" clear-trigger="always" placeholder="请输入手机号" />–>-->
|
||||
<!-- <van-field v-model="pwd" type="number" class="ui-user-input font_32 color3" placeholder="请输入密码" />-->
|
||||
|
||||
<!-- <div v-if="showChooseArea" class="ui-area-mask" @click="showChooseArea = false"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="ui-line-v2"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </van-tab>-->
|
||||
</van-tabs>
|
||||
</div>
|
||||
<div class="">
|
||||
<div v-if="active == 0" class="ui-signIn-btn f-fcc colorF font_36 bold" @click="save">登录</div>
|
||||
<!-- <div v-else class="ui-signIn-btn f-fcc colorF font_36 bold" @click="saveV2">登录</div>-->
|
||||
<!-- <div class="font_28 ui-pt-20 text-center color76" @click="active = active == 0 ? 1 : 0">-->
|
||||
<!-- {{ active == 1 ? '使用验证码登录' : '使用密码登录' }}-->
|
||||
<!-- <!– <span class="colorBussnessTheme" @click="active == 1 ? 0: 1"> 去登录</span>–>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="f-fcc">-->
|
||||
<!-- <div class="ui-pt-32 ui-agreement-box">-->
|
||||
<!-- <img v-if="!isAgreement" class="ui-agreement-icon" src="https://image.fulllinkai.com/202408/23/1e9f28b0187c276ee3bfc2137e8880e1.png" alt="" @click="isAgreement = !isAgreement" />-->
|
||||
<!-- <!– <img v-else class="ui-agreement-icon" src="https://image.fulllinkai.com/202408/23/0cd995a8298d57b6e3ae7c0f6d61ceac.png" alt="" @click="isAgreement = !isAgreement" />–>-->
|
||||
|
||||
<!-- <svg v-else class="ui-agreement-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" @click="isAgreement = !isAgreement">-->
|
||||
<!-- <circle cx="8" cy="8" r="7.5" stroke="#3d56bd" />-->
|
||||
<!-- <path d="M4 7.82705L6.61392 10.5862L12 5.2002" stroke="#3d56bd" stroke-linecap="round" />-->
|
||||
<!-- </svg>-->
|
||||
<!-- <div class="font_24 color76 ui-agreement-text" @click="isAgreement = !isAgreement">-->
|
||||
<!-- 我已阅读并同意-->
|
||||
<!-- <span class="colorBussnessTheme" @click.stop="jumpAgreement('appPrivacyAgreement')">《隐私协议》</span>-->
|
||||
<!-- 和-->
|
||||
<!-- <span class="colorBussnessTheme" @click.stop="jumpAgreement('appServeAgreement')">《服务协议》</span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { closeToast, showDialog, showLoadingToast, showToast } from 'vant';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
// import { backFillLoginData } from '@/plugins/public';
|
||||
|
||||
defineOptions({ name: 'ProfitLogin' });
|
||||
|
||||
const areaList = ref<any[]>([{ area_code: 86, label: '中国大陆', tips: '1开头, 11位手机号' }]);
|
||||
const AreaValue = ref('+86');
|
||||
const showChooseArea = ref(false);
|
||||
const AreaIndex = ref(0);
|
||||
|
||||
const active = ref<any>(0);
|
||||
const openId = ref<any>('');
|
||||
const email = ref<any>('');
|
||||
const mobile = ref<any>('');
|
||||
const code = ref<any>('');
|
||||
const emailCode = ref<any>('');
|
||||
const pwd = ref<any>('');
|
||||
const time = ref<any>(60);
|
||||
const timeV2 = ref<any>(60); // 邮箱验证码时间
|
||||
const timer = ref<any>(null);
|
||||
const timerV2 = ref<any>(null); // 邮箱倒计时
|
||||
const throttle = ref<any>(true);
|
||||
const codeThrottle = ref<any>(true);
|
||||
const isAgreement = ref(false); // 是否同意协议
|
||||
const isWechatDevice = ref(false); // 是否为微信设备
|
||||
|
||||
const isWeiXinBrowser = /micromessenger/i.test(navigator.userAgent);
|
||||
|
||||
const argument = ref<any>({
|
||||
videoid: '',
|
||||
userid: '',
|
||||
from_user_id: 0,
|
||||
});
|
||||
|
||||
const save = () => {
|
||||
let data = {
|
||||
mobile: mobile.value,
|
||||
area_code: 86,
|
||||
code: code.value,
|
||||
openid: localStorage.getItem('rt_openid'),
|
||||
};
|
||||
if (!mobile.value) {
|
||||
showToast('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (!code.value) {
|
||||
showToast('请输入验证码');
|
||||
return;
|
||||
}
|
||||
// if (!isAgreement.value) {
|
||||
// showToast('请先阅读并同意协议');
|
||||
// return;
|
||||
// }
|
||||
if (throttle.value) {
|
||||
throttle.value = false;
|
||||
showLoadingToast('');
|
||||
requestGo({ url: `/h5/v1/auth/register`, data, method: 'post' })
|
||||
.then((res) => {
|
||||
showToast('登录成功');
|
||||
throttle.value = true;
|
||||
let result = res.data;
|
||||
const userStore = useUserStore();
|
||||
userStore.userID = result.id;
|
||||
userStore.agentName = result.name || '----';
|
||||
userStore.agentAvatar = result.avatar || 'https://image.fulllinkai.com/202203/09/cc1c73eb1a4941fef25a15cd1ff2f9df.png';
|
||||
userStore.agentMobile = result.mobile || '';
|
||||
userStore.token = result.token;
|
||||
localStorage.setItem('rt_token', result.token);
|
||||
localStorage.setItem('rt_openid', result.openid as any);
|
||||
// backFillLoginData(result, userStore);
|
||||
setTimeout(() => {
|
||||
throttle.value = true;
|
||||
if (localStorage.getItem('jumpRtPathName') as any) {
|
||||
let queryData = JSON.parse(localStorage.getItem('jumpRtPathQuery') as any);
|
||||
let paramsData = JSON.parse(localStorage.getItem('jumpRtPathParams') as any);
|
||||
router.replace({
|
||||
name: localStorage.getItem('jumpRtPathName') as any,
|
||||
params: paramsData,
|
||||
query: queryData,
|
||||
});
|
||||
} else {
|
||||
router.replace({
|
||||
name: 'user',
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
localStorage.removeItem('jumpRtPathName');
|
||||
localStorage.removeItem('jumpRtPathQuery');
|
||||
localStorage.removeItem('jumpRtPathParams');
|
||||
}, 50);
|
||||
}, 1200);
|
||||
})
|
||||
.catch((err) => {
|
||||
throttle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
const saveV2 = () => {
|
||||
let data = {
|
||||
mobile: mobile.value,
|
||||
password: pwd.value,
|
||||
};
|
||||
if (!mobile.value) {
|
||||
showToast('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (!pwd.value) {
|
||||
showToast('请输入密码');
|
||||
return;
|
||||
}
|
||||
if (!isAgreement.value) {
|
||||
showToast('请先阅读并同意协议');
|
||||
return;
|
||||
}
|
||||
if (throttle.value) {
|
||||
throttle.value = false;
|
||||
showLoadingToast('');
|
||||
requestGo({ url: `/go/api/app/server/mobile/pwd/login`, data, method: 'post' })
|
||||
.then((res) => {
|
||||
showToast('登录成功');
|
||||
throttle.value = true;
|
||||
const userStore = useUserStore();
|
||||
userStore.token = res.data.token;
|
||||
localStorage.setItem('rt_token', res.data.token);
|
||||
setTimeout(() => {
|
||||
throttle.value = true;
|
||||
if (localStorage.getItem('jumpPLPathName') as any) {
|
||||
let queryData = JSON.parse(localStorage.getItem('jumpPLPathQuery') as any);
|
||||
let paramsData = JSON.parse(localStorage.getItem('jumpPLPathParams') as any);
|
||||
router.replace({
|
||||
name: localStorage.getItem('jumpPLPathName') as any,
|
||||
params: paramsData,
|
||||
query: queryData,
|
||||
});
|
||||
} else {
|
||||
console.log('3320');
|
||||
router.replace({
|
||||
name: 'appProfitUser',
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
localStorage.removeItem('jumpPLPathName');
|
||||
localStorage.removeItem('jumpPLPathQuery');
|
||||
localStorage.removeItem('jumpPLPathParams');
|
||||
}, 50);
|
||||
}, 1200);
|
||||
})
|
||||
.catch((err) => {
|
||||
throttle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getCode = () => {
|
||||
let data = {
|
||||
mobile: mobile.value,
|
||||
area_code: areaList.value[AreaIndex.value].area_code,
|
||||
};
|
||||
if (!mobile.value) {
|
||||
showToast('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (codeThrottle.value) {
|
||||
codeThrottle.value = false;
|
||||
showLoadingToast('');
|
||||
requestGo({ url: `/h5/v2/user/smscode`, data, hideLoading: true, method: 'post' })
|
||||
.then(() => {
|
||||
timer.value = setInterval(() => {
|
||||
time.value--;
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
showToast('验证码已发送');
|
||||
}, 1000);
|
||||
})
|
||||
.catch((err) => {
|
||||
codeThrottle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
// 发送邮箱验证
|
||||
const getEmailCode = () => {
|
||||
let data = {
|
||||
email: email.value,
|
||||
};
|
||||
if (!email.value) {
|
||||
showToast('请输入邮箱');
|
||||
return;
|
||||
}
|
||||
if (codeThrottle.value) {
|
||||
codeThrottle.value = false;
|
||||
showLoadingToast('');
|
||||
requestGo({ url: `h5/v2/user/emailcode`, data, hideLoading: true, method: 'post' })
|
||||
.then(() => {
|
||||
timerV2.value = setInterval(() => {
|
||||
timeV2.value--;
|
||||
}, 1000);
|
||||
setTimeout(() => {
|
||||
showToast('验证码已发送');
|
||||
}, 1000);
|
||||
})
|
||||
.catch((err) => {
|
||||
codeThrottle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const getAreaCode = () => {
|
||||
requestGo({ url: `/h5/v2/user/areacode/list`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
let result = res.data;
|
||||
areaList.value = result;
|
||||
console.log(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// const getQrcode = () => {
|
||||
// const u = navigator.userAgent;
|
||||
// const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
|
||||
// let data = {
|
||||
// from_user_id: argument.value.from_user_id,
|
||||
// open_id: openId.value,
|
||||
// platform: isAndroid ? 'Android' : 'IOS',
|
||||
// };
|
||||
// requestGo({ url: `/h5/v1/other/login/scan/qrcode`, data, hideLoading: true, method: 'post' })
|
||||
// .then(() => {})
|
||||
// .catch((err) => {
|
||||
// console.log(err);
|
||||
// });
|
||||
// };
|
||||
|
||||
// const openAppFn = () => {
|
||||
// if (isWechatDevice.value) {
|
||||
// showDialog({
|
||||
// title: '温馨提示',
|
||||
// confirmButtonText: '确认',
|
||||
// overlayStyle: { background: '#333333', opacity: 0.4 },
|
||||
// message: '请点击右上角按钮,然后在弹出的菜单中,点击在浏览器打开,即可安装',
|
||||
// })
|
||||
// .then(() => {})
|
||||
// .catch(() => {});
|
||||
// return;
|
||||
// }
|
||||
// showLoadingToast('');
|
||||
// const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
||||
// // 判断是否是iOS设备
|
||||
// const isIOS = /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream;
|
||||
// if (isIOS) {
|
||||
// // 尝试唤起iOS应用程序
|
||||
// const appUrl = 'yfheal://';
|
||||
// const appStoreUrl = 'https://apps.apple.com/cn/app/%E5%8F%8B%E7%A6%8F%E5%90%8C%E4%BA%AB/id6470103042';
|
||||
// setTimeout(function () {
|
||||
// if (!document.hidden) {
|
||||
// // window.location.href = appStoreUrl;
|
||||
// }
|
||||
// }, 2000);
|
||||
// // window.location.href = appUrl;
|
||||
// window.location.href = appStoreUrl;
|
||||
// } else if (/android/i.test(userAgent)) {
|
||||
// // 尝试唤起Android应用程序
|
||||
// // const appUrl = 'intent://yourapp/#Intent;scheme=yourappscheme;package=com.yourapp.package;end';
|
||||
// const appUrl = 'gqkcqn://';
|
||||
// const androidDownload = 'https://images.health.ufutx.com/apk/lovehealth.apk';
|
||||
// setTimeout(function () {
|
||||
// if (!document.hidden) {
|
||||
// window.location.href = androidDownload;
|
||||
// }
|
||||
// }, 800);
|
||||
// // window.location.href = appUrl;
|
||||
// } else {
|
||||
// console.log('设备类型未识别或不支持此操作。');
|
||||
// }
|
||||
// };
|
||||
|
||||
// 选择国家区号
|
||||
const selectedArea = (e, index) => {
|
||||
AreaValue.value = `+${e.area_code}`;
|
||||
AreaIndex.value = index;
|
||||
showChooseArea.value = !showChooseArea.value;
|
||||
};
|
||||
|
||||
const jumpAgreement = (url) => {
|
||||
router.push({
|
||||
name: url,
|
||||
});
|
||||
};
|
||||
|
||||
watch(time, () => {
|
||||
if (time.value == 0) {
|
||||
clearInterval(timer.value);
|
||||
timer.value = null;
|
||||
codeThrottle.value = true;
|
||||
time.value = 60;
|
||||
}
|
||||
});
|
||||
watch(timeV2, () => {
|
||||
if (timeV2.value == 0) {
|
||||
clearInterval(timerV2.value);
|
||||
timerV2.value = null;
|
||||
codeThrottle.value = true;
|
||||
timeV2.value = 60;
|
||||
}
|
||||
});
|
||||
const isWechatBrowser = () => {
|
||||
return /MicroMessenger/i.test(navigator.userAgent);
|
||||
};
|
||||
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-appDownloadPageV2 {
|
||||
background: #ffffff;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
padding-bottom: px2rem(160);
|
||||
}
|
||||
|
||||
.ui-top-logo {
|
||||
width: px2rem(320);
|
||||
height: px2rem(58);
|
||||
display: block;
|
||||
margin: px2rem(142) auto px2rem(80) auto;
|
||||
}
|
||||
|
||||
.ui-data-box {
|
||||
padding: 0 px2rem(74);
|
||||
}
|
||||
|
||||
.ui-area-code {
|
||||
padding-right: px2rem(20);
|
||||
white-space: nowrap;
|
||||
word-break: break-all;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.Angle_icon {
|
||||
width: px2rem(24);
|
||||
height: px2rem(24);
|
||||
display: block;
|
||||
margin-left: px2rem(4);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ui-area-mask {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 21;
|
||||
}
|
||||
|
||||
.area_code_choose_box {
|
||||
position: absolute;
|
||||
left: px2rem(90);
|
||||
top: px2rem(66);
|
||||
background: #ffffff;
|
||||
box-shadow: 0 px2rem(4) px2rem(28) 0 rgba(0, 0, 0, 0.08);
|
||||
border-radius: px2rem(8);
|
||||
z-index: 22;
|
||||
|
||||
.area_code_choose_list {
|
||||
max-height: px2rem(420);
|
||||
overflow-y: scroll;
|
||||
|
||||
.area_code_choose {
|
||||
padding: px2rem(24) px2rem(30) 0 px2rem(30);
|
||||
|
||||
.area_code_choose_item {
|
||||
word-break: break-all;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.selected_icon {
|
||||
width: px2rem(36);
|
||||
height: px2rem(36);
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.area_code_choose:last-child {
|
||||
padding-bottom: px2rem(30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.area_code_choose_box:before {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
top: px2rem(-24);
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
border-top: solid px2rem(12) transparent;
|
||||
border-left: solid px2rem(12) transparent;
|
||||
border-right: solid px2rem(12) transparent;
|
||||
border-bottom: solid px2rem(12) #ffffff;
|
||||
}
|
||||
|
||||
.ui-title {
|
||||
width: px2rem(130);
|
||||
height: px2rem(40);
|
||||
margin-right: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-user-input,
|
||||
.ui-user-input-v2 {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
background: initial;
|
||||
font-size: px2rem(40);
|
||||
}
|
||||
|
||||
.ui-user-input-v2 {
|
||||
width: px2rem(260);
|
||||
}
|
||||
.ui-user-input-v3 {
|
||||
width: px2rem(600);
|
||||
}
|
||||
|
||||
::v-deep(.van-search__content) {
|
||||
background: initial;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::v-deep(input::-webkit-input-placeholder) {
|
||||
color: #cccccc;
|
||||
font-size: px2rem(32);
|
||||
}
|
||||
|
||||
// 去除默认下划线
|
||||
::v-deep(.van-cell:after) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-code-btn {
|
||||
width: px2rem(170);
|
||||
padding: px2rem(14) 0;
|
||||
border-radius: px2rem(40);
|
||||
background: #18ca6e;
|
||||
}
|
||||
|
||||
.set {
|
||||
background: rgba(24, 202, 110, 0.1);
|
||||
}
|
||||
|
||||
.ui-line,
|
||||
.ui-line-v2 {
|
||||
width: 100%;
|
||||
height: px2rem(2);
|
||||
background: #f0f0f0;
|
||||
margin: px2rem(40) 0 px2rem(40) 0;
|
||||
}
|
||||
|
||||
.ui-line-v2 {
|
||||
margin: px2rem(40) 0 px2rem(40) 0;
|
||||
}
|
||||
|
||||
.ui-agreement-box {
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
padding-top: px2rem(120);
|
||||
|
||||
.ui-agreement-icon {
|
||||
width: px2rem(28);
|
||||
height: px2rem(28);
|
||||
display: block;
|
||||
margin-right: px2rem(12);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-agreement-text {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.colorBussnessTheme {
|
||||
color: #18ca6e;
|
||||
}
|
||||
.ui-signIn-btn {
|
||||
width: px2rem(640);
|
||||
height: px2rem(112);
|
||||
border-radius: px2rem(60);
|
||||
background: #18ca6e;
|
||||
margin: px2rem(140) auto 0 auto;
|
||||
}
|
||||
|
||||
:deep(.van-tab) {
|
||||
font-size: 20px;
|
||||
}
|
||||
:deep(.van-tabs__line) {
|
||||
width: 20px;
|
||||
height: 4px;
|
||||
background: #18ca6e;
|
||||
//background: linear-gradient(90deg, #18ca6e 0%, rgba(24, 202, 110, 0) 100%);
|
||||
}
|
||||
.appWatchTop-pic {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.appWatchBox {
|
||||
position: relative;
|
||||
animation: slide-down 1s ease forwards;
|
||||
@keyframes slide-down {
|
||||
from {
|
||||
top: -100px; /* 初始位置在上方,超出屏幕外 */
|
||||
}
|
||||
|
||||
to {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
241
src/views/subDir/dietaryHabitList.vue
Normal file
241
src/views/subDir/dietaryHabitList.vue
Normal file
@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div class="ui-newSurveyAuditList">
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model:loading="loading" :finished="finished" @load="getList">
|
||||
<div v-if="!refreshing && list.length == 0">
|
||||
<img class="ui-empty-data-icon" src="https://images.health.ufutx.com/202505/20/259f20509b57b36199ef7619f8d63733.png" alt="" />
|
||||
<div class="color6 font_15 text-center">暂无数据</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="ui-list-box">
|
||||
<div v-for="(item, index) in list" :key="index" class="ui-list-item" @click="jumpPath(item)">
|
||||
<div class="f-fbc">
|
||||
<div class="f-fcl">
|
||||
<img class="ui-user-pic" :src="item.user.avatar || 'https://image.fulllinkai.com/202307/18/449c3253ca2bbed9314d39977a486d0e.png'" alt="" />
|
||||
<div>
|
||||
<div class="f-fcl">
|
||||
<div class="font_15 color0E bold ellipsis_1 ui-user-name">{{ item.user.name }}</div>
|
||||
<img v-if="item.user.is_privacy == 1" alt="" class="ui-privacy" src="https://images.health.ufutx.com/202510/24/f5f69e5439e632defe963f6c9d0a9e36.png" />
|
||||
</div>
|
||||
<div class="font_12 color76c ui-pt-4">{{ item.create_time }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-btn-v4 f-fcc font_12">详情</div>
|
||||
</div>
|
||||
<div v-if="item.status > 0" class="ui-audit-list">
|
||||
<div>{{ item.operate_user_name }}</div>
|
||||
<div :class="item.status > 1 ? 'errorStatus' : 'successStatus'">【{{ statusFn(item.status, 1) }}】</div>
|
||||
<div>方案前健康调查表单</div>
|
||||
</div>
|
||||
<div v-if="item.other_status > 0" class="ui-audit-list">
|
||||
<div>{{ item.other_operate_user_name }}</div>
|
||||
<div :class="item.other_status > 1 ? 'errorStatus' : 'successStatus'">【{{ statusFn(item.other_status, 1) }}】</div>
|
||||
<div>方案前健康调查表单</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onActivated, onMounted, ref } from 'vue';
|
||||
import requestSurvey from '@/utils/request';
|
||||
import router from '@/router';
|
||||
|
||||
defineOptions({ name: 'NewSurveyAuditList' });
|
||||
|
||||
const serviceUserId = ref<any>('');
|
||||
const list = ref<any[]>([]); // 数据存储
|
||||
const noMore = ref(false); // 没有更多数据
|
||||
const refreshing = ref(true); // 上拉刷新false表示加载完成
|
||||
const finished = ref(false); // true表示数据全部加载完成
|
||||
const loading = ref(false); // false表示数据加载完成
|
||||
const page = ref(1); // 数据分页
|
||||
|
||||
const getList = () => {
|
||||
requestSurvey({ url: `/go/api/app/v1/other/get/before/dma/question/list?page=${page.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
if (list.value.length === 0 || page.value === 1) {
|
||||
list.value = result.data.map((item, index) => {
|
||||
item.listV2 = [
|
||||
{
|
||||
name: '蓝色',
|
||||
status: index > 1 ? 2 : 1,
|
||||
},
|
||||
];
|
||||
return item;
|
||||
});
|
||||
} else if (list.value.length >= 15) {
|
||||
result.data.forEach((item, index) => {
|
||||
item.listV2 = {
|
||||
name: '蓝色',
|
||||
status: index > 1 ? 2 : 1,
|
||||
};
|
||||
list.value.push(item);
|
||||
});
|
||||
}
|
||||
refreshing.value = false;
|
||||
loading.value = false;
|
||||
if (list.value.length < 15 || result.data.length < 15) {
|
||||
finished.value = true;
|
||||
noMore.value = true;
|
||||
}
|
||||
page.value++;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const onRefresh = () => {
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
finished.value = false;
|
||||
loading.value = true;
|
||||
getList();
|
||||
};
|
||||
|
||||
const jumpPath = (e) => {
|
||||
router.push({
|
||||
name: 'appSurveyExamine',
|
||||
query: { id: e.id, service_user_id: serviceUserId.value },
|
||||
});
|
||||
};
|
||||
|
||||
const statusFn = (status, type) => {
|
||||
let statusText = '';
|
||||
let typeText = '';
|
||||
switch (status) {
|
||||
case 1:
|
||||
statusText = '已通过';
|
||||
typeText = '通过原因';
|
||||
break;
|
||||
case 2:
|
||||
statusText = '已拒绝';
|
||||
typeText = '拒绝原因';
|
||||
break;
|
||||
case 3:
|
||||
statusText = '需要补充资料';
|
||||
typeText = '需要补充资料原因';
|
||||
break;
|
||||
}
|
||||
if (type == 1) {
|
||||
return statusText;
|
||||
} else if (type == 2) {
|
||||
return statusText;
|
||||
}
|
||||
};
|
||||
|
||||
onActivated(() => {
|
||||
if (list.value && list.value.length && localStorage.getItem('examine')) {
|
||||
let examine = JSON.parse(localStorage.getItem('examine') as any);
|
||||
list.value.forEach((item) => {
|
||||
if (item.id == examine.id) {
|
||||
item.status = examine.status;
|
||||
localStorage.removeItem('examine');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query;
|
||||
serviceUserId.value = route.service_user_id;
|
||||
// let data = {
|
||||
// mobile: '15622316024',
|
||||
// area_code: 86,
|
||||
// code: '009527',
|
||||
// };
|
||||
// requestSurvey({ url: `/api/app/mobile/register/login`, data, method: 'post' });
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-newSurveyAuditList {
|
||||
background: #ffffff;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
* {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-empty-data-icon {
|
||||
width: 135px; /* 原px2rem(270) */
|
||||
height: 100px; /* 原px2rem(200) */
|
||||
display: block;
|
||||
margin: 25vh auto 0 auto;
|
||||
}
|
||||
|
||||
.ui-list-box {
|
||||
padding: 16px 16px 100px 16px; /* 原px2rem(32) px2rem(32) px2rem(200) px2rem(32) */
|
||||
|
||||
.ui-list-item {
|
||||
padding-bottom: 20px; /* 原px2rem(40) */
|
||||
margin-bottom: 20px; /* 原px2rem(40) */
|
||||
border-bottom: 1px solid #dddddd; /* 原px2rem(2) */
|
||||
|
||||
.ui-user-pic {
|
||||
width: 40px; /* 原px2rem(80) */
|
||||
height: 40px; /* 原px2rem(80) */
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
margin-right: 10px; /* 原px2rem(20) */
|
||||
}
|
||||
|
||||
.ui-user-name {
|
||||
max-width: 200px; /* 原px2rem(400) */
|
||||
}
|
||||
.ui-privacy {
|
||||
margin-left: 10px;
|
||||
width: 59.4px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.ui-btn,
|
||||
.ui-btn-v2,
|
||||
.ui-btn-v3,
|
||||
.ui-btn-v4 {
|
||||
padding: 0 10px;
|
||||
//width: 66px; /* 原px2rem(132) */
|
||||
height: 32px; /* 原px2rem(64) */
|
||||
border-radius: 20px; /* 原px2rem(40) */
|
||||
background: #3554c5;
|
||||
}
|
||||
|
||||
.ui-btn-v2 {
|
||||
color: #3554c5;
|
||||
background: #eff3ff;
|
||||
}
|
||||
|
||||
.ui-btn-v3 {
|
||||
color: #ff2946;
|
||||
background: #fff2f2;
|
||||
}
|
||||
|
||||
.ui-btn-v4 {
|
||||
color: #66676c;
|
||||
background: #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-audit-list {
|
||||
margin-top: 10px;
|
||||
padding: 4px 5px;
|
||||
display: flex;
|
||||
border-radius: 4px;
|
||||
background: #f8f8f8;
|
||||
font-size: 12px;
|
||||
.successStatus {
|
||||
color: #3554c5;
|
||||
}
|
||||
.errorStatus {
|
||||
color: #ff2946;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
374
src/views/subDir/dietaryHabitTest.vue
Normal file
374
src/views/subDir/dietaryHabitTest.vue
Normal file
File diff suppressed because one or more lines are too long
893
src/views/subDir/leaseShopDetail.vue
Normal file
893
src/views/subDir/leaseShopDetail.vue
Normal file
@ -0,0 +1,893 @@
|
||||
<template>
|
||||
<div v-if="loading" class="ui-leaseShopDetail">
|
||||
<van-swipe :autoplay="3000" lazy-render>
|
||||
<van-swipe-item v-for="image in banner" :key="image" class="ui-relative">
|
||||
<img class="ui-mall-pic" :src="image" alt="" />
|
||||
</van-swipe-item>
|
||||
<template #indicator="{ active, total }">
|
||||
<div class="custom-indicator font_26 colorF">{{ active + 1 }}/{{ total }}</div>
|
||||
</template>
|
||||
</van-swipe>
|
||||
<div class="ui-shop-detail-container">
|
||||
<div class="ui-shop-data-box">
|
||||
<div class="f-fcl">
|
||||
<span class="font_28 ui-price-symbol bold">¥</span>
|
||||
<div class="font_44 ui-show-price bold"><span v-html="htmlPrice"></span></div>
|
||||
<div class="font_28 ui-original-price color6">¥{{ originPrice }}</div>
|
||||
</div>
|
||||
<div class="font_32 color3 bold ui-pt-10">{{ title }}</div>
|
||||
</div>
|
||||
<div class="ui-ExpressDelivery-data-box">
|
||||
<div>
|
||||
<div class="f-fcl font_28">
|
||||
<span class="color9 ui-pr-24">配送</span>
|
||||
<span class="ui-pr-24">广东深圳</span>
|
||||
<span v-if="freightPrice != '0.00' || freightPrice != 0" class="ui-pl-24 ui-relative ui-distribution-address">运费:{{ freightPrice }}</span>
|
||||
</div>
|
||||
<!-- <div class="font_28 ui-pt-24">-->
|
||||
<!-- <span class="color9 ui-pr-24">服务</span>-->
|
||||
<!-- <span class="color3">支持7天无理由退货</span>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="describe" class="ui-relative ui-pt-40">
|
||||
<img class="ui-line-icon" src="https://image.fulllinkai.com/202405/15/266a22038e0122c70fc282f00c78dbc7.png" alt="" />
|
||||
<div class="font_26 color3 ui-line-text">商品详情</div>
|
||||
</div>
|
||||
<div class="font_28 color3 ui-detail-introduce">
|
||||
<richTextParsing :rich-text="describe"></richTextParsing>
|
||||
</div>
|
||||
<div class="ui-bottom-operation f-fbc">
|
||||
<div class="ui-operation-icon-box" @click="isShowPoster">
|
||||
<img class="ui-operation-icon" src="https://image.fulllinkai.com/202405/15/b18fc23a9956849ddbead6882fa60bb9.png" alt="" />
|
||||
<div class="font_20 color6 text-center">分享</div>
|
||||
</div>
|
||||
<div class="ui-buy-btn f-fcc font_30 colorF" @click="showBug = true">立即购买</div>
|
||||
</div>
|
||||
<sharePosterV2 ref="openSharePoster">
|
||||
<template #sharePoster>
|
||||
<!--生成海报html容器-->
|
||||
<div id="capture" class="ui-poster-container">
|
||||
<div class="ui-user-avatar-box f-fcc">
|
||||
<div class="ui-user-avatar backCover" :style="{ background: 'url(' + canvasData.avatar + ')' }"></div>
|
||||
<div class="color3 font_22 ui-ml-8 ui-user-name-box f-fcc">
|
||||
<div v-if="shareName">{{ shareName }}</div>
|
||||
<div>推荐一个好物给你</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-poster-pic-box">
|
||||
<img class="ui-poster-pic" :src="canvasData.pic" alt="" />
|
||||
</div>
|
||||
<div class="ui-poster-data-box">
|
||||
<div class="ui-mt-20 ui-ml-20">
|
||||
<div class="f-fcl">
|
||||
<span class="font_24 ui-poster-price-symbol">¥</span>
|
||||
<div class="font_40 ui-poster-price"><span v-html="htmlSharePrice"></span></div>
|
||||
</div>
|
||||
<div class="font_24 ellipsis_2 ui-poster-title color3">{{ title }}</div>
|
||||
<!-- <div class="font_24 ellipsis_2 ui-poster-title color9 ui-mt-10">{{ title }}</div>-->
|
||||
</div>
|
||||
<div class="ui-poster-qrcode-box">
|
||||
<img class="ui-poster-qrcode" :src="canvasData.qrcode" alt="" />
|
||||
<div class="font_20 color6 text-center">长按保存图片至相册</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</sharePosterV2>
|
||||
<van-popup v-model:show="showBug" round position="bottom" :duration="0.5">
|
||||
<div class="ui-bug-box">
|
||||
<img class="ui-close-icon" src="https://image.fulllinkai.com/202405/16/20161b3e74af1eacd328181ff40b0358.png" alt="" @click="showBug = false" />
|
||||
<div class="ui-buy-detail-box">
|
||||
<img class="ui-buy-pic" :src="icon" alt="" />
|
||||
<div>
|
||||
<div class="ellipsis_2 font_32 color333 bold ui-buy-title">{{ title }}</div>
|
||||
<div class="f-fcl ui-buy-price color3 font_24"> 已选:{{ spuData.spec[spuIndex].name }} {{ spuSubIndex !== null ? spuSubData.spec[spuSubIndex].name : '' }} </div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="spuData.name" class="ui-sku-box">
|
||||
<div class="ui-sku-list">
|
||||
<div class="font_28 color3 bold">{{ spuData.name }}</div>
|
||||
<div class="f-fcl f-wrap">
|
||||
<div v-for="(item, index) in spuData.spec" :key="index" class="font_26 f-fbc color3 ui-pt-16" @click="selectSku(index)">
|
||||
<div class="ui-sku-item" :class="spuIndex == index ? 'ui-sku-item-active colorF' : 'color3'">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="spuSubData.name" class="ui-pt-36">
|
||||
<div class="font_28 color3 bold">{{ spuSubData.name }}</div>
|
||||
<div class="f-fcl f-wrap">
|
||||
<div v-for="(item, index) in spuSubData.spec" :key="index" class="font_26 f-fbc color3 ui-pt-16" @click="selectSubSku(index)">
|
||||
<div class="ui-sku-item" :class="spuSubIndex == index ? 'ui-sku-item-active colorF' : 'color3'">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-num-box f-fbc ui-pt-28">
|
||||
<div class="font_24 color6"><span class="font_28 color3 ui-mr-16">数量</span>库存:{{ stock }}</div>
|
||||
<div class="f-fcr ui-num-input-box">
|
||||
<div class="ui-relative f-fcl">
|
||||
<div class="font_40 color6 ui-num-input-minus" @click="numMinus()">
|
||||
<div class="ui-num-minus">-</div>
|
||||
</div>
|
||||
<div class="ui-select-input font_28">{{ num }}</div>
|
||||
<div class="font_40 color6 ui-num-input-add" @click="numAdd()">
|
||||
<div class="ui-num-minus-v2">+</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-total-price-box">
|
||||
<div class="f-fcl">
|
||||
<div class="font_24 color6">合计金额:</div>
|
||||
<div v-if="calculating" class="font_24 color6 bold">计算中...</div>
|
||||
<div v-else-if="num == 0" class="font_24 color6">库存不足</div>
|
||||
<div v-else class="f-fcl bold ui-total-price">
|
||||
<span class="font_28 ui-buy-price-symbol">¥</span>
|
||||
<div class="font_44"><span v-html="htmlTotalPrice"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="policyTitle" class="ui-confirm-bottom-box">
|
||||
<div class="f-fcc">
|
||||
<img v-show="!isAgreement" class="ui-agreement-icon" src="https://image.fulllinkai.com/202405/16/fae039c670338fe6743b7f6a8803ec43.png" alt="" @click="isAgreement = !isAgreement" />
|
||||
<img v-show="isAgreement" class="ui-agreement-icon" src="https://image.fulllinkai.com/202405/16/c27533426d24451aceba94e4fe316e88.png" alt="" @click="isAgreement = !isAgreement" />
|
||||
<div class="font_24 color6" @click="isAgreement = !isAgreement">
|
||||
已阅读并同意<span class="ui-agreement-text" @click.stop="jumpAgreement">{{ policyTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-confirm-btn font_32 f-fcc colorF bold" @click="payment">立即支付</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, onDeactivated, onActivated } from 'vue';
|
||||
import qrcode from 'qrcode';
|
||||
import { showToast } from 'vant';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
import { weXinShare } from '@/plugins/wxShare';
|
||||
import { examineRegister, imageConversion } from '@/plugins/public';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
defineOptions({ name: 'LeaseShopDetail' });
|
||||
|
||||
const userStore = useUserStore() as any;
|
||||
const loading = ref(false);
|
||||
const showBug = ref(false);
|
||||
const timer = ref<any>(null);
|
||||
const isAgreement = ref(false); // 是否同意协议
|
||||
|
||||
const id = ref<any>('');
|
||||
const title = ref<any>('');
|
||||
const icon = ref<any>('');
|
||||
const policyId = ref<any>('');
|
||||
const policyTitle = ref<any>('');
|
||||
const banner = ref<any[]>([]); // 轮播图
|
||||
const describe = ref<any>(); // 详情富文本
|
||||
const num = ref<any>(0); // 购买数量
|
||||
const skuIds = ref<any>('');
|
||||
const skuIdDataList = ref<any[]>([]);
|
||||
const stock = ref<any>(0); // 选中的sku剩余库存
|
||||
const calculating = ref<any>(false); // 是否显示价格计算中
|
||||
|
||||
const spuData = ref<any>({}); // spu一级数据
|
||||
const spuSubData = ref<any>({}); // spu二级数据
|
||||
|
||||
const spuIndex = ref(0); // spu一级选中下标
|
||||
const spuSubIndex = ref<any>(null); // spu二级选中下标
|
||||
|
||||
const htmlPrice = ref<any>(''); // 详情展示价格
|
||||
const htmlSharePrice = ref<any>(''); // 分享展示价格
|
||||
const shareName = ref<any>('');
|
||||
const htmlTotalPrice = ref<any>('0'); // 总价展示价格
|
||||
const originPrice = ref<any>(0); // 原价
|
||||
const freightPrice = ref<any>(0); // 邮费
|
||||
|
||||
const canvasData = ref<any>({ background: '', avatar: '', pic: '', qrcode: '' }); // 分享所需要的图片数据
|
||||
const openSharePoster = ref<any>(); // 分享按钮组件事件
|
||||
|
||||
// 获取商品详情
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/spu/detail/${id.value}`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
|
||||
banner.value = [];
|
||||
result.spu.banner = JSON.parse(result.spu.banner);
|
||||
if (result.spu.banner && result.spu.banner.length > 0) {
|
||||
banner.value = result.spu.banner;
|
||||
} else {
|
||||
banner.value.push(result.spu.icon);
|
||||
}
|
||||
describe.value = result.spu.description;
|
||||
title.value = result.spu.title;
|
||||
icon.value = result.spu.icon;
|
||||
policyId.value = result.spu.policy_id;
|
||||
policyTitle.value = result.spu.policy_title;
|
||||
|
||||
result.spu.spec = JSON.parse(result.spu.spec);
|
||||
spuData.value = result.spu.spec;
|
||||
|
||||
spuSubData.value = {};
|
||||
// 默认选中第一个sku
|
||||
if (spuData.value.name && spuData.value.spec[spuIndex.value].sub_spec) {
|
||||
spuSubData.value = spuData.value.spec[spuIndex.value].sub_spec;
|
||||
spuSubIndex.value = 0;
|
||||
}
|
||||
|
||||
skuIds.value = '';
|
||||
// 循环出所有的skuid
|
||||
spuData.value.spec.forEach((item) => {
|
||||
if (item.skuid) {
|
||||
skuIds.value += `${skuIds.value ? ',' : ''}${item.skuid}`;
|
||||
}
|
||||
if (item.sub_spec) {
|
||||
recursion(item);
|
||||
}
|
||||
});
|
||||
|
||||
if (`${result.sku_default.price}`.includes('.')) {
|
||||
let splitPrice = result.sku_default.price.split('.');
|
||||
htmlSharePrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlSharePrice.value = result.sku_default.price;
|
||||
}
|
||||
|
||||
shareName.value = userStore.agentName ? (userStore.agentName.length > 4 ? `${userStore.agentName.slice(0, 4)}...` : userStore.agentName) : '';
|
||||
|
||||
// 根据循环出所有的skuid获取每一个skuid的库存
|
||||
getSkuIdStock();
|
||||
|
||||
weXinShare('https://image.fulllinkai.com/202310/28/88e931a50ec0a8094fb46191b389457e.png', `https://health.ufutx.com/store/#/leaseShopDetail/${id.value}?from_user_id=${userStore.userID}&from_type=rt_${id.value}`, '友福商城', '邀请您进入友福商城');
|
||||
|
||||
let text = `https://health.ufutx.com/store/#/leaseShopDetail/${id.value}?from_user_id=${userStore.userID}&from_type=rt_${id.value}`;
|
||||
qrcode.toDataURL(text, (err, url) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
// 分享二维码图片转base64
|
||||
canvasData.value.qrcode = url;
|
||||
}
|
||||
});
|
||||
|
||||
// 分享背景图片转base64
|
||||
imageConversion('https://image.fulllinkai.com/202111/02/f23994d8fd3088c833a8bbf2bfdf6de5.png').then((res) => {
|
||||
canvasData.value.background = res;
|
||||
});
|
||||
// 分享用户头像图片转base64
|
||||
imageConversion(`${userStore.agentAvatar}`).then((res) => {
|
||||
canvasData.value.avatar = res;
|
||||
});
|
||||
// 分享活动图片转base64
|
||||
imageConversion(`${result.spu.icon}`).then((res) => {
|
||||
canvasData.value.pic = res;
|
||||
});
|
||||
console.log(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取所有skuid库存
|
||||
const getSkuIdStock = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/sku/${skuIds.value}`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
console.log(result, '77777');
|
||||
skuIdDataList.value = result;
|
||||
|
||||
if (skuIdDataList.value && skuIdDataList.value.length > 0) {
|
||||
gainSelectStock();
|
||||
}
|
||||
|
||||
num.value = 1;
|
||||
prepay('init');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取选中的sku库存
|
||||
const gainSelectStock = () => {
|
||||
let id;
|
||||
if (spuSubIndex.value !== null) {
|
||||
id = spuSubData.value.spec[spuSubIndex.value].skuid;
|
||||
} else {
|
||||
id = spuData.value.spec[spuIndex.value].skuid;
|
||||
}
|
||||
skuIdDataList.value.forEach((item) => {
|
||||
if (item.id == id) {
|
||||
stock.value = item.stock;
|
||||
originPrice.value = item.price;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 递归循环所有skuid
|
||||
const recursion = (e) => {
|
||||
e.sub_spec.spec.forEach((item) => {
|
||||
if (item.skuid) {
|
||||
skuIds.value += `${skuIds.value ? ',' : ''}${item.skuid}`;
|
||||
}
|
||||
if (item.sub_spec) {
|
||||
recursion(item.sub_spec.spec);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取预计算价格
|
||||
const prepay = (e) => {
|
||||
let id = '';
|
||||
if (spuSubIndex.value !== null) {
|
||||
id = spuSubData.value.spec[spuSubIndex.value].skuid;
|
||||
} else {
|
||||
id = spuData.value.spec[spuIndex.value].skuid;
|
||||
}
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/sku/prepay/${id}/${e == 'init' ? 1 : num.value}/1`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
// originPrice.value = result.price_origin;
|
||||
freightPrice.value = result.freight;
|
||||
loading.value = true;
|
||||
if (e == 'init') {
|
||||
if (`${result.price}`.includes('.')) {
|
||||
let splitPrice = result.price.split('.');
|
||||
htmlPrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlPrice.value = result.price;
|
||||
}
|
||||
if (!stock.value) {
|
||||
num.value = 0;
|
||||
}
|
||||
}
|
||||
if (`${result.price}`.includes('.')) {
|
||||
let splitPrice = result.price.split('.');
|
||||
htmlTotalPrice.value = `${splitPrice[0]}.<span class="font_32">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlTotalPrice.value = result.price;
|
||||
}
|
||||
calculating.value = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// Sku 数量减少
|
||||
const numMinus = () => {
|
||||
if (num.value <= 1) {
|
||||
return;
|
||||
}
|
||||
num.value--;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
};
|
||||
|
||||
// Sku 数量增加
|
||||
const numAdd = () => {
|
||||
if (num.value >= stock.value) {
|
||||
showToast('超出限购或商品库存上限');
|
||||
return;
|
||||
}
|
||||
num.value++;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
};
|
||||
|
||||
// 支付
|
||||
const payment = () => {
|
||||
let data = {} as any;
|
||||
let spuId;
|
||||
if (spuSubIndex.value !== null) {
|
||||
spuId = spuSubData.value.spec[spuSubIndex.value].skuid;
|
||||
} else {
|
||||
spuId = spuData.value.spec[spuIndex.value].skuid;
|
||||
}
|
||||
|
||||
data.id = id.value;
|
||||
data.skuId = spuId;
|
||||
data.spuNum = num.value;
|
||||
data.spuName = spuData.value.spec[spuIndex.value].name;
|
||||
data.spuSubName = spuSubIndex.value !== null ? spuSubData.value.spec[spuSubIndex.value].name : '';
|
||||
|
||||
// 没有资料先去注册,注册后回到分享的指定页面
|
||||
if (userStore.registerAgent == '0') {
|
||||
examineRegister(router.currentRoute.value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (num.value <= 0) {
|
||||
showToast('请先选择购买数量');
|
||||
return;
|
||||
}
|
||||
|
||||
if (policyTitle.value && !isAgreement.value) {
|
||||
showToast('请先阅读并同意协议');
|
||||
return;
|
||||
}
|
||||
|
||||
router.push({
|
||||
name: 'leaseShopOrderConfirm',
|
||||
query: { orderData: JSON.stringify(data) },
|
||||
});
|
||||
};
|
||||
|
||||
const selectSku = (index) => {
|
||||
if (spuIndex.value == index) {
|
||||
return;
|
||||
}
|
||||
htmlTotalPrice.value = '0';
|
||||
spuIndex.value = index;
|
||||
if (spuData.value.spec[index].sub_spec) {
|
||||
spuSubData.value = spuData.value.spec[index].sub_spec;
|
||||
spuSubIndex.value = 0;
|
||||
} else {
|
||||
spuSubData.value = {};
|
||||
spuSubIndex.value = null;
|
||||
}
|
||||
|
||||
num.value = 0;
|
||||
if (skuIdDataList.value && skuIdDataList.value.length > 0) {
|
||||
gainSelectStock();
|
||||
}
|
||||
|
||||
if (stock.value) {
|
||||
num.value = 1;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
}
|
||||
};
|
||||
|
||||
const selectSubSku = (index) => {
|
||||
if (spuSubIndex.value == index) {
|
||||
return;
|
||||
}
|
||||
htmlTotalPrice.value = '0';
|
||||
spuSubData.value = spuData.value.spec[spuIndex.value].sub_spec;
|
||||
spuSubIndex.value = index;
|
||||
num.value = 0;
|
||||
|
||||
if (skuIdDataList.value && skuIdDataList.value.length > 0) {
|
||||
gainSelectStock();
|
||||
}
|
||||
|
||||
if (stock.value) {
|
||||
num.value = 1;
|
||||
calculating.value = true;
|
||||
prepay('calculate');
|
||||
}
|
||||
};
|
||||
|
||||
const isShowPoster = () => {
|
||||
if (canvasData.value.background && canvasData.value.avatar && canvasData.value.pic && canvasData.value.qrcode) {
|
||||
openSharePoster.value.isShow();
|
||||
}
|
||||
};
|
||||
|
||||
const jumpAgreement = () => {
|
||||
router.push({
|
||||
name: 'shopAgreement',
|
||||
params: { id: policyId.value },
|
||||
query: { title: policyTitle.value },
|
||||
});
|
||||
};
|
||||
|
||||
// 离开时清除生成的海报
|
||||
onDeactivated(() => {
|
||||
openSharePoster.value.remove();
|
||||
});
|
||||
|
||||
onActivated(() => {
|
||||
let route = router.currentRoute.value.params;
|
||||
if (id.value != route.id) {
|
||||
id.value = route.id;
|
||||
loading.value = false;
|
||||
showBug.value = false;
|
||||
spuIndex.value = 0;
|
||||
spuSubIndex.value = null;
|
||||
getDetail();
|
||||
} else {
|
||||
// 分享用户头像图片转base64
|
||||
imageConversion(`${userStore.agentAvatar}`).then((res) => {
|
||||
canvasData.value.avatar = res;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-leaseShopDetail {
|
||||
background: #f4f4f4;
|
||||
overflow-y: scroll;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.ui-mall-pic {
|
||||
width: 100vw;
|
||||
height: px2rem(750);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.custom-indicator {
|
||||
position: absolute;
|
||||
right: px2rem(20);
|
||||
bottom: px2rem(20);
|
||||
border-radius: px2rem(8);
|
||||
padding: px2rem(8) px2rem(14);
|
||||
letter-spacing: px2rem(4);
|
||||
background: #aaaaaa;
|
||||
}
|
||||
|
||||
.ui-shop-detail-container {
|
||||
padding: px2rem(24);
|
||||
|
||||
.ui-shop-data-box,
|
||||
.ui-ExpressDelivery-data-box {
|
||||
padding: px2rem(30) px2rem(24);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
margin-bottom: px2rem(24);
|
||||
|
||||
.ui-price-symbol {
|
||||
margin-right: px2rem(2);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-show-price,
|
||||
.ui-price-symbol {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-original-price {
|
||||
text-decoration: line-through;
|
||||
margin-left: px2rem(16);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-ExpressDelivery-data-box {
|
||||
.ui-distribution-address:after {
|
||||
content: '';
|
||||
width: px2rem(2);
|
||||
height: px2rem(22);
|
||||
background: #d8d8d8;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: px2rem(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-line-icon {
|
||||
width: px2rem(310);
|
||||
height: px2rem(12);
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.ui-line-text {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: px2rem(28);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.ui-detail-introduce {
|
||||
padding: px2rem(20) 0 px2rem(120) 0;
|
||||
background: #ffffff;
|
||||
margin-top: px2rem(30);
|
||||
|
||||
.ui-introduce-height {
|
||||
width: 100vw;
|
||||
height: px2rem(260);
|
||||
background: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-bottom-operation {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
padding: px2rem(18) px2rem(24) px2rem(18) 0;
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-top: px2rem(2) solid #f5f5f5;
|
||||
|
||||
.ui-operation-icon-box {
|
||||
flex: 1;
|
||||
|
||||
.ui-operation-icon {
|
||||
width: px2rem(44);
|
||||
height: px2rem(44);
|
||||
display: block;
|
||||
margin: 0 auto px2rem(2) auto;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-btn {
|
||||
width: px2rem(480);
|
||||
height: px2rem(88);
|
||||
background: #2a63b2;
|
||||
border-radius: px2rem(24);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-poster-container {
|
||||
position: relative;
|
||||
position: fixed;
|
||||
top: -100000;
|
||||
left: 0;
|
||||
z-index: -99999;
|
||||
border-radius: px2rem(16);
|
||||
width: px2rem(482);
|
||||
height: px2rem(806);
|
||||
padding: 0 px2rem(30) px2rem(30) px2rem(30);
|
||||
background: #f7f7f7;
|
||||
box-sizing: border-box;
|
||||
background-size: cover !important;
|
||||
background-position: center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
|
||||
.ui-user-avatar-box {
|
||||
width: px2rem(440);
|
||||
height: px2rem(48);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(40);
|
||||
margin-top: px2rem(8);
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
top: px2rem(10);
|
||||
z-index: 10;
|
||||
|
||||
.ui-user-avatar {
|
||||
width: px2rem(28);
|
||||
height: px2rem(28);
|
||||
border-radius: 50%;
|
||||
margin-left: px2rem(18);
|
||||
}
|
||||
|
||||
.ui-user-name-box {
|
||||
margin-top: px2rem(-6);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-poster-pic-box,
|
||||
.ui-poster-data-box {
|
||||
width: px2rem(450);
|
||||
height: px2rem(450);
|
||||
border-radius: px2rem(16);
|
||||
background: #ffffff;
|
||||
position: absolute;
|
||||
top: px2rem(80);
|
||||
left: px2rem(16);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-poster-pic {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: px2rem(16);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-poster-data-box {
|
||||
top: px2rem(546);
|
||||
height: px2rem(244);
|
||||
|
||||
.ui-poster-title {
|
||||
width: px2rem(226);
|
||||
line-height: px2rem(36);
|
||||
max-width: px2rem(226);
|
||||
margin-top: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-poster-price,
|
||||
.ui-poster-price-symbol {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-poster-price-symbol {
|
||||
margin-right: px2rem(2);
|
||||
margin-top: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-poster-qrcode-box {
|
||||
.ui-poster-qrcode {
|
||||
width: px2rem(200);
|
||||
height: px2rem(200);
|
||||
border-radius: px2rem(16);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
margin-bottom: px2rem(-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-bug-box {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding-bottom: px2rem(60);
|
||||
border-radius: px2rem(24);
|
||||
|
||||
.ui-close-icon {
|
||||
position: absolute;
|
||||
right: px2rem(24);
|
||||
top: px2rem(24);
|
||||
z-index: 22;
|
||||
width: px2rem(48);
|
||||
height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-buy-detail-box {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
height: px2rem(160);
|
||||
position: relative;
|
||||
padding: px2rem(30) px2rem(30) 0 px2rem(30);
|
||||
|
||||
.ui-buy-pic {
|
||||
width: px2rem(160);
|
||||
min-width: px2rem(160);
|
||||
height: px2rem(160);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
margin-right: px2rem(16);
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
}
|
||||
|
||||
.ui-buy-title {
|
||||
max-width: px2rem(440);
|
||||
line-height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-buy-price {
|
||||
position: absolute;
|
||||
bottom: px2rem(-12);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-price-symbol {
|
||||
margin-right: px2rem(2);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-total-price-box {
|
||||
padding-top: px2rem(40);
|
||||
|
||||
.ui-total-price {
|
||||
color: #cc352f;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-user-input {
|
||||
width: px2rem(532);
|
||||
box-sizing: border-box;
|
||||
border: px2rem(2) solid #f5f5f5;
|
||||
border-radius: px2rem(16);
|
||||
padding: px2rem(16) px2rem(30);
|
||||
}
|
||||
|
||||
::v-deep(input::-webkit-input-placeholder) {
|
||||
font-weight: initial;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
// 去除默认下划线
|
||||
::v-deep(.van-cell:after) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-sku-box {
|
||||
padding: px2rem(40) px2rem(30) px2rem(24) px2rem(30);
|
||||
|
||||
.ui-sku-list {
|
||||
.ui-sku-item,
|
||||
.ui-sku-item-active {
|
||||
padding: px2rem(12) px2rem(24);
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(20);
|
||||
}
|
||||
|
||||
.ui-sku-item-active {
|
||||
background: #2a63b2;
|
||||
}
|
||||
|
||||
.ui-active-sku {
|
||||
background: #e8fff7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-num-box {
|
||||
.ui-num-input-box {
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #ececec;
|
||||
|
||||
.ui-num-input-minus,
|
||||
.ui-num-input-add {
|
||||
width: px2rem(56);
|
||||
height: px2rem(56);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.ui-num-minus,
|
||||
.ui-num-minus-v2 {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.ui-num-minus {
|
||||
top: 43%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-num-input-minus {
|
||||
border-right: px2rem(2) solid #ececec;
|
||||
}
|
||||
|
||||
.ui-num-input-add {
|
||||
border-left: px2rem(2) solid #ececec;
|
||||
}
|
||||
|
||||
.ui-select-input {
|
||||
width: px2rem(44);
|
||||
border: none;
|
||||
text-align: center;
|
||||
padding: px2rem(4) px2rem(20);
|
||||
background: initial;
|
||||
line-height: px2rem(40);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-confirm-btn {
|
||||
width: px2rem(638);
|
||||
height: px2rem(88);
|
||||
background: #2a63b2;
|
||||
border-radius: px2rem(24);
|
||||
margin: px2rem(28) auto 0 auto;
|
||||
}
|
||||
|
||||
.ui-confirm-bottom-box {
|
||||
padding-top: px2rem(28);
|
||||
border-top: px2rem(2) solid #eaeaea;
|
||||
|
||||
.ui-agreement-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
vertical-align: top;
|
||||
margin-right: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-agreement-text {
|
||||
color: #2a63b2;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
640
src/views/subDir/leaseShopOrderConfirm.vue
Normal file
640
src/views/subDir/leaseShopOrderConfirm.vue
Normal file
@ -0,0 +1,640 @@
|
||||
<template>
|
||||
<div v-if="loading" class="ui-leaseShopOrderConfirm">
|
||||
<div class="ui-m-inf">
|
||||
<div class="ui-relative">
|
||||
<div class="f-fbc">
|
||||
<div v-for="(item, index) in receivingList" :key="index" class="font_28 f-fcc ui-receiving-item" :class="receivingIndex == index ? 'colorBlue font_30 bold' : 'color3'" @click="selectSymptom(index)">
|
||||
<div class="ui-receiving-text">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img v-show="receivingIndex == 0" class="ui-receiving-icon" src="https://image.fulllinkai.com/202404/09/122fe1183af7e8e15dfa3ea4b5ba861f.png" alt="" @click="selectSymptom(1)" />
|
||||
<img v-show="receivingIndex == 1" class="ui-receiving-icon-v2" src="https://image.fulllinkai.com/202404/09/64e3443b623f73dd341389fc53e303e8.png" alt="" @click="selectSymptom(0)" />
|
||||
</div>
|
||||
<div class="ui-address-box">
|
||||
<div v-if="receivingIndex == 0">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">自提地址:</div>
|
||||
<div class="font_28 color3 ui-address-content">广东省深圳市南山区南新路阳光科创中心B座33楼3301(荔林地铁站C口步行170米)</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/3b4a522e6bdb081a14186712f87cb20b.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">自提人:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ userStore.agentName }},{{ userStore.agentMobile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else @click="openWx">
|
||||
<div v-if="detailedAddress">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">收货地址:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ detailedAddress }}</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/3b4a522e6bdb081a14186712f87cb20b.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">收货人:</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ address.userName }},{{ address.telNumber }}</div>
|
||||
</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="ui-address-item ui-pt-6 ui-pb-32">
|
||||
<div class="font_28 color3 bold">点击添加收货地址</div>
|
||||
<img class="ui-address-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<img class="ui-decoration-icon" src="https://image.fulllinkai.com/202309/20/e8a30e7308236eb3894fec737b66657d.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-inf-box">
|
||||
<div class="ui-m-avt-lst ui-relative">
|
||||
<img class="ui-pic" :src="icon" alt="" />
|
||||
<div class="ui-m-lst-ri">
|
||||
<div class="font_32 ellipsis_2 bold ui-title">{{ title }}</div>
|
||||
<div class="font_28 ui-product-spu-name color6">已选:{{ orderData.spuName }}{{ orderData.spuSubName ? ';' + orderData.spuSubName : '' }}</div>
|
||||
<div class="font_28 color3 ui-product-num">X {{ orderData.spuNum }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-mt-40">
|
||||
<div class="font_28 color3">商品总额</div>
|
||||
<div class="font_28 bold"><span class="ui-buy-price-symbol">¥</span>{{ totalPrices }}</div>
|
||||
</div>
|
||||
<div v-if="receivingIndex != 0" class="f-fbc ui-mt-20">
|
||||
<div class="font_28 color3">快递费用</div>
|
||||
<div class="font_28"><span class="ui-buy-price-symbol">¥</span>{{ freightPrice }}</div>
|
||||
</div>
|
||||
<div v-if="related.share_user_name || related.invite_user_name || related.referrer_user_name">
|
||||
<div v-if="related.share_user_name" class="f-fbc ui-mt-22">
|
||||
<div class="font_28 color3">分享用户</div>
|
||||
<div class="font_28 bold color6">{{ related.share_user_name }}</div>
|
||||
</div>
|
||||
<div v-if="related.invite_user_name" class="f-fbc ui-mt-22">
|
||||
<div class="font_28 color3">邀请用户</div>
|
||||
<div class="font_28 bold color6">{{ related.invite_user_name }}</div>
|
||||
</div>
|
||||
<div v-if="related.referrer_user_name" class="f-fbc ui-mt-22">
|
||||
<div class="font_28 color3">推荐用户</div>
|
||||
<div class="font_28 bold color6">{{ related.referrer_user_name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="f-fbc ui-mt-22">
|
||||
<div class="font_28 color3">关联信息</div>
|
||||
<div class="font_28 bold color6">暂无关联信息</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="f-fbc ui-mt-20">-->
|
||||
<!-- <div class="font_28 color3">服务</div>-->
|
||||
<!-- <div class="font_28">七天无理由退货</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="ui-discounts-box f-fbc">
|
||||
<div></div>
|
||||
<div class="f-fcr">
|
||||
<div class="font_28 color3">应付金额:</div>
|
||||
<div class="f-fcl ui-buy-price">
|
||||
<span class="font_28 ui-buy-price-symbol bold">¥</span>
|
||||
<div class="font_32 bold"><span v-html="htmlTotalPrices"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-remark-box font_28 f-fbc" @click="showRemark = true">
|
||||
<div class="color3">订单备注</div>
|
||||
<div class="ui-remark-text">
|
||||
<div class="f-fcr text-right">
|
||||
<div class="ui-mr-10 ellipsis_1" :class="remark ? 'color3' : 'color6'">{{ remark ? remark : '请填写备注' }}</div>
|
||||
<img class="ui-remark-triangle-icon" src="https://image.fulllinkai.com/202405/16/c7baecb6a93780e115b54d9602ff06b3.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-operation-box f-fbc">
|
||||
<div class="font_24 color3 f-fcl">
|
||||
合计:
|
||||
<div class="f-fcl ui-buy-price">
|
||||
<span class="font_28 ui-buy-price-symbol bold">¥</span>
|
||||
<div class="font_44 bold"><span v-html="htmlTotalPrices"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-buy-btn f-fcc colorF font_30 bold" @click="payment">确认支付</div>
|
||||
</div>
|
||||
<van-popup v-model:show="showRemark" round position="bottom" :duration="0.5">
|
||||
<div class="ui-remark-input-box">
|
||||
<img class="ui-close-icon" src="https://image.fulllinkai.com/202405/16/20161b3e74af1eacd328181ff40b0358.png" alt="" @click="(showRemark = false), (remark = '')" />
|
||||
<div class="text-center color3 font_32 bold">订单备注</div>
|
||||
<van-field v-model="remark" type="textarea" autosize rows="5" show-word-limit class="ui-remark-input f-fcc font_40 color3 bold" :maxlength="200" placeholder="请填写备注" />
|
||||
<div class="font_32 colorF f-fcc ui-remark-btn" @click="showRemark = false">确认</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { closeToast, showToast, showDialog } from 'vant';
|
||||
import wx from 'weixin-js-sdk';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
defineOptions({ name: 'LeaseShopOrderConfirm' });
|
||||
|
||||
const userStore = useUserStore() as any;
|
||||
const throttle = ref(true);
|
||||
const orderData = ref<any>({});
|
||||
const loading = ref<any>(false);
|
||||
const timer = ref<any>(null);
|
||||
|
||||
const receivingIndex = ref(1);
|
||||
const receivingList = ref<any[]>(['线下自提', '物流配送']);
|
||||
|
||||
const related = ref<any>({}); // 关联分享、推荐、介绍用户信息
|
||||
const title = ref<any>('');
|
||||
const icon = ref<any>('');
|
||||
const showRemark = ref(false);
|
||||
const remark = ref<any>('');
|
||||
|
||||
const totalPrices = ref<any>(0); // 合计价格
|
||||
const htmlTotalPrices = ref<any>(0); // 合计价格小数点字号
|
||||
const freightPrice = ref<any>(0); // 邮费
|
||||
const totalNumber = ref<any>(0);
|
||||
|
||||
const wxPay = ref<any>(null); // 支付所需config
|
||||
const tradeId = ref<any>(''); // 订单ID
|
||||
const tradeNo = ref<any>(''); // 订单号
|
||||
|
||||
const detailedAddress = ref<any>('');
|
||||
const address = ref<any>({
|
||||
userName: '',
|
||||
postalCode: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
countyName: '',
|
||||
detailInfo: '',
|
||||
nationalCode: '',
|
||||
telNumber: '',
|
||||
});
|
||||
|
||||
// 获取商品详情
|
||||
const getDetail = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/spu/detail/${orderData.value.id}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
title.value = result.spu.title;
|
||||
icon.value = result.spu.icon;
|
||||
related.value = result.related_person_detail;
|
||||
// 获取上一次记录的物流配送地址
|
||||
if (result.recive && result.recive.address) {
|
||||
address.value.userName = result.recive.name;
|
||||
address.value.telNumber = result.recive.mobile;
|
||||
detailedAddress.value = result.recive.address;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取预计算价格
|
||||
const prepay = () => {
|
||||
clearTimeout(timer.value);
|
||||
timer.value = setTimeout(() => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/sku/prepay/${orderData.value.skuId}/${orderData.value.spuNum}/${receivingIndex.value == 0 ? 1 : 2}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
freightPrice.value = result.freight;
|
||||
totalNumber.value = result.total_number;
|
||||
loading.value = true;
|
||||
// 小数点后面字号变小
|
||||
if (`${result.total}`.includes('.')) {
|
||||
let splitPrice = result.total.split('.');
|
||||
htmlTotalPrices.value = `${splitPrice[0]}.<span class="font_28">${splitPrice[1]}</span>`;
|
||||
} else {
|
||||
htmlTotalPrices.value = result.total;
|
||||
}
|
||||
totalPrices.value = result.price;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 支付
|
||||
const payment = () => {
|
||||
let data = {
|
||||
num: orderData.value.spuNum * 1,
|
||||
remark: remark.value,
|
||||
total_number: totalNumber.value,
|
||||
from_source: 'rt',
|
||||
spu_id: orderData.value.id * 1,
|
||||
sku_id: orderData.value.skuId * 1,
|
||||
ship: receivingIndex.value == 0 ? 1 : 2,
|
||||
name: receivingIndex.value == 0 ? userStore.agentName : address.value.userName,
|
||||
mobile: receivingIndex.value == 0 ? userStore.agentMobile : address.value.telNumber,
|
||||
address: receivingIndex.value == 0 ? '广东省深圳市南山区南新路阳光科创中心B座33楼3301(荔林地铁站C口步行170米)' : detailedAddress.value,
|
||||
pay_type: 1,
|
||||
};
|
||||
if (receivingIndex.value == 1) {
|
||||
if (!detailedAddress.value) {
|
||||
showToast('请填写收货地址');
|
||||
return;
|
||||
}
|
||||
if (!address.value.userName) {
|
||||
showToast('请填写你的姓名');
|
||||
return;
|
||||
}
|
||||
if (!address.value.telNumber) {
|
||||
showToast('请填写你的手机号');
|
||||
return;
|
||||
}
|
||||
if (!/^1(3|4|5|6|7|8|9)\d{9}$/.test(address.value.telNumber)) {
|
||||
showToast('请输入正确的手机号码');
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (throttle.value) {
|
||||
throttle.value = false;
|
||||
requestGo({ url: `h5/v2/shop/rental/buy`, data, method: 'post' })
|
||||
.then((res) => {
|
||||
if (res.code == 7) {
|
||||
showDialog({
|
||||
title: '温馨提示',
|
||||
message: '价格已经发生变化,请重新确认',
|
||||
}).then(() => {
|
||||
throttle.value = true;
|
||||
prepay();
|
||||
});
|
||||
return;
|
||||
}
|
||||
let result = res.data;
|
||||
wxPay.value = result.config;
|
||||
tradeId.value = result.order.id;
|
||||
tradeNo.value = result.order.trade_no;
|
||||
if (wxPay.value && (wxPay.value.appid || wxPay.value.appId)) {
|
||||
wx.config({
|
||||
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
|
||||
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
|
||||
appId: wxPay.value.appid || wxPay.value.appId, // 必填,微信的appID
|
||||
timestamp: wxPay.value.timeStamp, // 必填,生成签名的时间戳
|
||||
nonceStr: wxPay.value.nonceStr, // 必填,生成签名的随机串
|
||||
signature: wxPay.value.paySign, // 必填,签名,见 附录-JS-SDK使用权限签名算法
|
||||
jsApiList: ['chooseWXPay'], // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
|
||||
});
|
||||
wx.checkJsApi({
|
||||
jsApiList: ['chooseWXPay'], // 需要检测的JS接口列表
|
||||
success(res) {
|
||||
console.log(res);
|
||||
},
|
||||
});
|
||||
wx.ready(function () {
|
||||
throttle.value = true;
|
||||
wx.chooseWXPay({
|
||||
timestamp: wxPay.value.timeStamp,
|
||||
nonceStr: wxPay.value.nonceStr,
|
||||
package: wxPay.value.package,
|
||||
signType: wxPay.value.signType,
|
||||
paySign: wxPay.value.paySign,
|
||||
// 支付成功后的回调函数
|
||||
success(res) {
|
||||
if (res.errMsg === 'chooseWXPay:ok') {
|
||||
console.log(res);
|
||||
callBack();
|
||||
if (userStore.isAgent == 2) {
|
||||
userStore.isAgent = 1;
|
||||
}
|
||||
showToast('支付成功');
|
||||
setTimeout(() => {
|
||||
throttle.value = true;
|
||||
}, 1200);
|
||||
}
|
||||
},
|
||||
// 支付取消回调函数
|
||||
cancel() {
|
||||
throttle.value = true;
|
||||
showToast('取消支付');
|
||||
},
|
||||
// 支付失败回调函数
|
||||
fail() {
|
||||
throttle.value = true;
|
||||
showToast('支付失败');
|
||||
},
|
||||
});
|
||||
});
|
||||
wx.error(function (res) {
|
||||
throttle.value = true;
|
||||
console.log(res);
|
||||
});
|
||||
} else if (result.prepay_code == 4) {
|
||||
showToast('支付成功');
|
||||
if (userStore.isAgent == 2) {
|
||||
userStore.isAgent = 1;
|
||||
}
|
||||
setTimeout(() => {
|
||||
throttle.value = true;
|
||||
router.push({
|
||||
name: 'shopOrderDetail',
|
||||
params: { id: tradeId.value },
|
||||
});
|
||||
}, 1200);
|
||||
} else {
|
||||
showToast('支付失败');
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
throttle.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取最后一次物流地址信息
|
||||
const getMailData = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/order/express/last`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
if (result && result.mobile) {
|
||||
detailedAddress.value = result.address;
|
||||
address.value.userName = result.name;
|
||||
address.value.telNumber = result.mobile;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const callBack = () => {
|
||||
requestGo({ url: `h5/v2/shop/rental/wechatpay/callback/${tradeNo.value}`, hideLoading: true, method: 'post' })
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
closeToast();
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取微信收货地址
|
||||
const openWx = () => {
|
||||
if (receivingIndex.value == 0) {
|
||||
return;
|
||||
}
|
||||
wx.openAddress({
|
||||
success(res) {
|
||||
address.value.userName = res.userName; // 收货人姓名
|
||||
address.value.postalCode = res.postalCode; // 邮编
|
||||
address.value.provinceName = res.provinceName; // 国标收货地址第一级地址(省)
|
||||
address.value.cityName = res.cityName; // 国标收货地址第二级地址(市)
|
||||
address.value.countryName = res.countryName; // 国标收货地址第三级地址(国家)
|
||||
address.value.detailInfo = res.detailInfo; // 详细收货地址信息
|
||||
address.value.nationalCode = res.nationalCode; // 收货地址国家码
|
||||
address.value.telNumber = res.telNumber; // 收货人手机号码
|
||||
detailedAddress.value = `${res.provinceName}` + `${res.cityName}` + `${res.countryName}` + `${res.detailInfo}`;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 选择收货方式
|
||||
const selectSymptom = (index) => {
|
||||
receivingIndex.value = index;
|
||||
prepay();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.query;
|
||||
orderData.value = JSON.parse(route.orderData as any);
|
||||
|
||||
prepay();
|
||||
getMailData();
|
||||
getDetail();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-leaseShopOrderConfirm {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-m-inf {
|
||||
padding: px2rem(30);
|
||||
|
||||
.ui-receiving-item {
|
||||
width: 50%;
|
||||
height: px2rem(88);
|
||||
margin-top: px2rem(-6);
|
||||
|
||||
.ui-receiving-text {
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
white-space: nowrap;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-receiving-icon,
|
||||
.ui-receiving-icon-v2 {
|
||||
width: 100%;
|
||||
height: px2rem(88);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ui-receiving-icon-v2 {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-address-box {
|
||||
padding: px2rem(24) px2rem(24) px2rem(12) px2rem(24);
|
||||
margin-bottom: px2rem(24);
|
||||
background: #ffffff;
|
||||
border-radius: 0 0 px2rem(16) px2rem(16);
|
||||
position: relative;
|
||||
|
||||
.ui-address-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-address-title-box {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
||||
.ui-address-title {
|
||||
width: px2rem(132);
|
||||
text-align: justify;
|
||||
text-align-last: justify;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.ui-address-content {
|
||||
width: px2rem(440);
|
||||
max-width: px2rem(440);
|
||||
margin-left: px2rem(20);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-address-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
margin-top: px2rem(4);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-decoration-icon {
|
||||
width: px2rem(664);
|
||||
height: px2rem(4);
|
||||
position: absolute;
|
||||
bottom: px2rem(2);
|
||||
left: px2rem(14);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-inf-box,
|
||||
.ui-remark-box {
|
||||
padding: px2rem(24);
|
||||
margin-bottom: px2rem(20);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-m-avt-lst {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.ui-pic {
|
||||
width: px2rem(160);
|
||||
height: px2rem(160);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
display: block;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-m-lst-ri {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-title {
|
||||
max-width: px2rem(462);
|
||||
line-height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-product-spu-name {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.ui-product-num {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ui-total-price {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: px2rem(6);
|
||||
|
||||
.ui-total-original-price {
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-discounts-box {
|
||||
padding-top: px2rem(20);
|
||||
border-top: px2rem(2) solid #eaeaea;
|
||||
margin-top: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-buy-num-box {
|
||||
padding: 0 px2rem(22);
|
||||
height: px2rem(56);
|
||||
background: #f7f7f7;
|
||||
border-radius: px2rem(8);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-remark-box {
|
||||
.ui-remark-text {
|
||||
max-width: px2rem(400);
|
||||
}
|
||||
|
||||
.ui-remark-triangle-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-price {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-buy-price-symbol {
|
||||
margin-right: px2rem(4);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
|
||||
.ui-operation-box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
padding: px2rem(16) px2rem(24) px2rem(16) px2rem(30);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-buy-btn {
|
||||
width: px2rem(400);
|
||||
height: px2rem(88);
|
||||
border-radius: px2rem(24);
|
||||
background: #2a63b2;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-remark-input-box {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding: px2rem(30) px2rem(30) px2rem(60) px2rem(30);
|
||||
border-radius: px2rem(24);
|
||||
|
||||
.ui-close-icon {
|
||||
position: absolute;
|
||||
right: px2rem(24);
|
||||
top: px2rem(24);
|
||||
z-index: 22;
|
||||
width: px2rem(48);
|
||||
height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-remark-input {
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin: px2rem(40) 0 px2rem(24) 0;
|
||||
}
|
||||
|
||||
.ui-remark-btn {
|
||||
width: 100%;
|
||||
height: px2rem(88);
|
||||
border-radius: px2rem(8);
|
||||
background: #2a63b2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
501
src/views/subDir/leaseShopOrderDetail.vue
Normal file
501
src/views/subDir/leaseShopOrderDetail.vue
Normal file
@ -0,0 +1,501 @@
|
||||
<template>
|
||||
<div class="ui-leaseShopOrderDetail">
|
||||
<div class="ui-m-inf">
|
||||
<div v-if="ship" class="ui-address-box">
|
||||
<div class="ui-address-item">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">{{ ship == 1 ? '自提地址:' : '邮寄地址:' }}</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ detailedAddress }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-address-item ui-pt-32 ui-pb-32">
|
||||
<div class="ui-address-title-box">
|
||||
<div class="ui-address-title font_28 color3 bold">{{ ship == 1 ? '自提人:' : '收货人:' }}</div>
|
||||
<div class="font_28 color3 ui-address-content">{{ address.userName }},{{ address.telNumber }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<img class="ui-decoration-icon" src="https://image.fulllinkai.com/202309/20/e8a30e7308236eb3894fec737b66657d.png" alt="" />
|
||||
</div>
|
||||
<div class="ui-inf-box">
|
||||
<div class="ui-m-avt-lst ui-relative">
|
||||
<img class="ui-pic" :src="orderData.icon" alt="" />
|
||||
<div class="ui-m-lst-ri">
|
||||
<div class="font_32 ellipsis_2 bold ui-title">{{ orderData.title }}</div>
|
||||
<div class="font_28 ui-product-num color6">X {{ orderData.num }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-mt-40">
|
||||
<div class="font_28 color3">商品总额</div>
|
||||
<div class="font_28 bold"><span class="ui-buy-price-symbol">¥</span>{{ orderData.price_final }}</div>
|
||||
</div>
|
||||
<div class="f-fbc ui-mt-20">
|
||||
<div class="font_28 color3">快递费用</div>
|
||||
<div class="font_28"><span class="ui-buy-price-symbol">¥</span>{{ orderData.freight }}</div>
|
||||
</div>
|
||||
<!-- <div class="f-fbc ui-mt-20">-->
|
||||
<!-- <div class="font_28 color3">服务</div>-->
|
||||
<!-- <div class="font_28">七天无理由退货</div>-->
|
||||
<!-- </div>-->
|
||||
<div class="ui-discounts-box f-fbc">
|
||||
<div></div>
|
||||
<div class="f-fcr">
|
||||
<div class="font_28 color3">应付金额:</div>
|
||||
<div class="font_32 bold ui-buy-price"><span class="ui-buy-price-symbol">¥</span>{{ orderData.total }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-inf-box">
|
||||
<div class="font_28 color3 bold ui-pb-12">订单信息</div>
|
||||
<div class="f-fcl font_28 ui-pt-16">
|
||||
<div class="color6 ui-pr-24 ui-inf-title">订单编号</div>
|
||||
<div class="ui-tradeNo ui-pr-24 ui-relative color3 ellipsis_1 text-right">{{ orderData.trade_no }}</div>
|
||||
<div class="colorBlue ui-pl-24 ui-inf-title" @click="onCopy(orderData.trade_no)">复制</div>
|
||||
</div>
|
||||
<div class="f-fcl font_28 ui-pt-16">
|
||||
<div class="color6 ui-pr-24 ui-inf-title">下单时间</div>
|
||||
<div class="color3">{{ orderData.created_at }}</div>
|
||||
</div>
|
||||
<div class="f-fcl font_28 ui-pt-16">
|
||||
<div class="color6 ui-pr-24 ui-inf-title">支付方式</div>
|
||||
<div class="color3">线上支付</div>
|
||||
</div>
|
||||
<div v-if="orderData.remark" class="f-fl font_28 ui-pt-16">
|
||||
<div class="color6 ui-pr-24 ui-inf-title">订单备注</div>
|
||||
<div ref="remarkText" class="ui-remark-text color3">{{ orderData.remark }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-operation-box f-fbc">
|
||||
<div></div>
|
||||
<div class="f-fcr">
|
||||
<div v-if="orderData.invoice_pics" class="ui-state-btn f-fcc color3 font_28" @click="imagePreview()">查看发票</div>
|
||||
<div class="ui-state-btn f-fcc color3 font_28" @click="showStatus = true">订单状态</div>
|
||||
<div class="ui-state-btn f-fcc color3 font_28 ui-ml-20" @click="jumpPath()">再次购买</div>
|
||||
<div v-if="expressStatus != 5 && expressStatus != 6" class="ui-again-buy-btn f-fcc colorF font_28 ui-ml-20" @click="signFor">确认收货</div>
|
||||
</div>
|
||||
</div>
|
||||
<van-popup v-model:show="showStatus" round position="bottom" :duration="0.5">
|
||||
<div class="ui-status-box">
|
||||
<img class="ui-close-icon" src="https://image.fulllinkai.com/202405/16/20161b3e74af1eacd328181ff40b0358.png" alt="" @click="showStatus = false" />
|
||||
<div class="font_32 color3 text-center bold ui-pt-32 ui-status-title">订单状态</div>
|
||||
<div class="ui-status-data-box">
|
||||
<div v-for="(item, index) in statusList" :key="index" class="f-fbc ui-status-data-item ui-relative">
|
||||
<div class="f-fcl">
|
||||
<div class="ui-status-big-circle f-fcc" :class="index == 0 ? 'ui-status-big-circle-bg' : ''">
|
||||
<div class="ui-status-circle" :class="index == 0 ? 'ui-status-circle-bg' : ''"></div>
|
||||
</div>
|
||||
<div v-if="item.status == 1" class="font_28 color6 ui-pl-24">未支付</div>
|
||||
<div v-else-if="item.status == 2" class="font_28 color6 ui-pl-24">已支付</div>
|
||||
<div v-else-if="item.status == 3" class="font_28 color6 ui-pl-24">退款中</div>
|
||||
<div v-else-if="item.status == 4" class="font_28 color6 ui-pl-24">已退款</div>
|
||||
<div v-else-if="item.status == 5" class="font_28 color6 ui-pl-24">退款被拒绝</div>
|
||||
<div v-else-if="item.status == 11" class="font_28 color6 ui-pl-24">待审核</div>
|
||||
<div v-else-if="item.status == 12" class="font_28 color6 ui-pl-24">审核不通过</div>
|
||||
<div v-else-if="item.status == 13" class="font_28 color6 ui-pl-24">待发货</div>
|
||||
<div v-else-if="item.status == 14" class="font_28 color6 ui-pl-24">已发货</div>
|
||||
<div v-else-if="item.status == 15" class="font_28 color6 ui-pl-24">已签收</div>
|
||||
<div v-else-if="item.status == 16" class="font_28 color6 ui-pl-24">已退款</div>
|
||||
</div>
|
||||
<div class="font_28 color6">{{ item.created_at }}</div>
|
||||
<div v-if="index + 1 != statusList.length" class="ui-status-line"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { showConfirmDialog, showImagePreview, showLoadingToast, showToast } from 'vant';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
import router from '@/router';
|
||||
import { copy } from '@/plugins/public';
|
||||
|
||||
defineOptions({ name: 'LeaseShopOrderDetail' });
|
||||
|
||||
const orderData = ref<any>({});
|
||||
const id = ref<any>('');
|
||||
|
||||
const showStatus = ref(false);
|
||||
const ship = ref<any>('');
|
||||
const expressId = ref<any>('');
|
||||
const expressStatus = ref<any>('');
|
||||
|
||||
const remarkText = ref<any>(null);
|
||||
// const showExpand = ref(false);
|
||||
|
||||
const statusList = ref<any[]>([]);
|
||||
|
||||
const detailedAddress = ref<any>('');
|
||||
const address = ref<any>({
|
||||
userName: '',
|
||||
postalCode: '',
|
||||
provinceName: '',
|
||||
cityName: '',
|
||||
countyName: '',
|
||||
detailInfo: '',
|
||||
nationalCode: '',
|
||||
telNumber: '',
|
||||
});
|
||||
|
||||
// 获取订单详情
|
||||
const getOrderDetail = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/order/detail/${id.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
orderData.value = result;
|
||||
orderData.value.freight = (result.freight / 100).toFixed(2);
|
||||
orderData.value.price_final = (result.price_final / 100).toFixed(2);
|
||||
orderData.value.total = orderData.value.freight * 1 + orderData.value.price_final * 1;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取订单状态详情
|
||||
const getPickUp = () => {
|
||||
requestGo({ url: `h5/v2/shop/rental/order/express/logs/${id.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
statusList.value = result;
|
||||
console.log(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取订单物流包裹详情
|
||||
const getLogistics = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/order/express/list/${id.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
console.log(result, '8888');
|
||||
if (result && result.length > 0) {
|
||||
detailedAddress.value = result[0].address;
|
||||
address.value.userName = result[0].name;
|
||||
address.value.telNumber = result[0].mobile;
|
||||
ship.value = result[0].ship;
|
||||
expressId.value = result[0].id;
|
||||
expressStatus.value = result[0].status;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 签收商品
|
||||
const signFor = () => {
|
||||
showConfirmDialog({
|
||||
title: '温馨提示',
|
||||
message: `是否确认签收?`,
|
||||
})
|
||||
.then(() => {
|
||||
showLoadingToast('');
|
||||
requestGo({ url: `h5/v2/shop/rental/express/sign/${expressId.value}`, method: 'post' })
|
||||
.then(() => {
|
||||
showToast('签收成功');
|
||||
expressStatus.value = 5;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// on cancel
|
||||
});
|
||||
};
|
||||
|
||||
const jumpPath = () => {
|
||||
if (orderData.value.spu_id == 0) {
|
||||
showToast('该商品已经下架');
|
||||
return;
|
||||
}
|
||||
router.push({
|
||||
name: 'leaseShopDetail',
|
||||
params: { id: orderData.value.spu_id },
|
||||
});
|
||||
};
|
||||
// 查看发票
|
||||
const imagePreview = () => {
|
||||
let images = JSON.parse(orderData.value.invoice_pics);
|
||||
showImagePreview({
|
||||
images,
|
||||
showIndex: false,
|
||||
loop: false,
|
||||
});
|
||||
};
|
||||
const onCopy = (e) => {
|
||||
copy(e, 0);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
let route = router.currentRoute.value.params;
|
||||
id.value = route.id;
|
||||
|
||||
getOrderDetail();
|
||||
getPickUp();
|
||||
getLogistics();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-leaseShopOrderDetail {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.ui-m-inf {
|
||||
padding: px2rem(30) px2rem(30) px2rem(200) px2rem(30);
|
||||
|
||||
.ui-address-box {
|
||||
padding: px2rem(24) px2rem(24) px2rem(4) px2rem(24);
|
||||
margin-bottom: px2rem(24);
|
||||
background: #ffffff;
|
||||
border-radius: 0 0 px2rem(16) px2rem(16);
|
||||
position: relative;
|
||||
|
||||
.ui-address-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-address-title-box {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
||||
.ui-address-title {
|
||||
width: px2rem(132);
|
||||
text-align: justify;
|
||||
text-align-last: justify;
|
||||
}
|
||||
|
||||
.ui-address-content {
|
||||
width: px2rem(498);
|
||||
max-width: px2rem(498);
|
||||
margin-left: px2rem(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-decoration-icon {
|
||||
width: px2rem(664);
|
||||
height: px2rem(4);
|
||||
position: absolute;
|
||||
bottom: px2rem(2);
|
||||
left: px2rem(14);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-inf-box {
|
||||
padding: px2rem(24);
|
||||
margin-bottom: px2rem(20);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-inf-title {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ui-sku-list {
|
||||
padding: px2rem(24);
|
||||
background: #f4f4f4;
|
||||
border-radius: px2rem(8);
|
||||
margin-bottom: px2rem(12);
|
||||
}
|
||||
|
||||
.ui-m-avt-lst {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.ui-pic {
|
||||
width: px2rem(160);
|
||||
height: px2rem(160);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
display: block;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(16);
|
||||
}
|
||||
|
||||
.ui-m-lst-ri {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-title {
|
||||
max-width: px2rem(320);
|
||||
line-height: px2rem(38);
|
||||
}
|
||||
|
||||
.ui-product-num {
|
||||
position: relative;
|
||||
bottom: px2rem(-2);
|
||||
}
|
||||
|
||||
.ui-total-price {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: px2rem(6);
|
||||
|
||||
.ui-total-original-price {
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-discounts-box {
|
||||
padding-top: px2rem(20);
|
||||
border-top: px2rem(2) solid #eaeaea;
|
||||
margin-top: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-show-more-box {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
z-index: 22;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
.ui-take-btn {
|
||||
width: px2rem(152);
|
||||
height: px2rem(56);
|
||||
background: #2a63b2;
|
||||
border-radius: px2rem(8);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-triangle-icon {
|
||||
width: px2rem(32);
|
||||
height: px2rem(32);
|
||||
display: block;
|
||||
margin-left: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-tradeNo {
|
||||
width: px2rem(380);
|
||||
}
|
||||
|
||||
.ui-tradeNo:before {
|
||||
content: '';
|
||||
width: px2rem(4);
|
||||
height: px2rem(20);
|
||||
background: #d8d8d8;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: px2rem(6);
|
||||
}
|
||||
|
||||
.ui-address {
|
||||
width: px2rem(440);
|
||||
text-align-last: right;
|
||||
}
|
||||
|
||||
.ui-remark-text {
|
||||
width: px2rem(440);
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-price {
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-buy-price-symbol {
|
||||
margin-right: px2rem(4);
|
||||
margin-top: px2rem(2);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-operation-box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
padding: px2rem(24) px2rem(15) px2rem(50) px2rem(15);
|
||||
box-sizing: border-box;
|
||||
z-index: 999;
|
||||
|
||||
.ui-again-buy-btn {
|
||||
width: px2rem(168);
|
||||
height: px2rem(64);
|
||||
border-radius: px2rem(8);
|
||||
background: #2a63b2;
|
||||
}
|
||||
|
||||
.ui-state-btn {
|
||||
width: px2rem(164);
|
||||
height: px2rem(60);
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #d8d8d8;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-status-box {
|
||||
position: relative;
|
||||
background: #ffffff;
|
||||
padding-bottom: px2rem(80);
|
||||
border-radius: px2rem(24);
|
||||
|
||||
.ui-close-icon {
|
||||
position: absolute;
|
||||
right: px2rem(24);
|
||||
top: px2rem(24);
|
||||
z-index: 22;
|
||||
width: px2rem(48);
|
||||
height: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-status-title {
|
||||
padding-bottom: px2rem(48);
|
||||
}
|
||||
|
||||
.ui-status-data-box {
|
||||
padding: 0 px2rem(30) px2rem(30) px2rem(30);
|
||||
min-height: px2rem(160);
|
||||
max-height: px2rem(480);
|
||||
overflow-y: scroll;
|
||||
|
||||
.ui-status-data-item {
|
||||
padding-bottom: px2rem(50);
|
||||
|
||||
.ui-status-big-circle {
|
||||
width: px2rem(36);
|
||||
height: px2rem(36);
|
||||
border-radius: 50%;
|
||||
|
||||
.ui-status-circle {
|
||||
width: px2rem(12);
|
||||
height: px2rem(12);
|
||||
border-radius: 50%;
|
||||
background: #d8d8d8;
|
||||
}
|
||||
|
||||
.ui-status-circle-bg {
|
||||
background: #2a63b2;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-status-big-circle-bg {
|
||||
background: rgba(42, 99, 178, 0.2);
|
||||
}
|
||||
|
||||
.ui-status-line {
|
||||
width: px2rem(4);
|
||||
height: px2rem(34);
|
||||
position: absolute;
|
||||
bottom: px2rem(2);
|
||||
left: px2rem(16);
|
||||
background: #d8d8d8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
289
src/views/subDir/leaseShopOrderList.vue
Normal file
289
src/views/subDir/leaseShopOrderList.vue
Normal file
@ -0,0 +1,289 @@
|
||||
<template>
|
||||
<div ref="scrollDistance" class="ui-leaseShopOrderList" @scroll="handleScroll">
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model:loading="loading" :finished="finished" @load="getList">
|
||||
<div v-if="loadingState && list.length == 0">
|
||||
<img class="ui-no-data-icon" src="https://image.fulllinkai.com/202406/03/3e513a3dac7b6d19d5c0bfc73a7d2c4c.png" alt="" />
|
||||
<div class="color6 font_30 text-center">暂无数据</div>
|
||||
</div>
|
||||
<div v-else class="ui-m-inf">
|
||||
<div v-for="(item, index) in list" :key="index" class="ui-inf-box" @click="jumpPath('leaseShopOrderDetail', item.id)">
|
||||
<div class="f-fbc">
|
||||
<div class="font_28 color3 bold">{{ item.created_at }}</div>
|
||||
<div v-if="item.status == 6" class="font_28 color6">已完成</div>
|
||||
<div v-else-if="item.express_status == 4" class="font_28 color6">已发货</div>
|
||||
<div v-else-if="item.express_status == 5" class="font_28 color6">已签收</div>
|
||||
<div v-else-if="item.express_status == 6" class="font_28 colorPrice">已退款</div>
|
||||
<div v-else class="font_28 color6">待发货</div>
|
||||
</div>
|
||||
<div class="ui-separate-line"></div>
|
||||
<div class="ui-m-avt-lst ui-relative">
|
||||
<img class="ui-pic" :src="item.icon" alt="" />
|
||||
<div class="ui-m-lst-ri font_28 color3">
|
||||
<div class="ellipsis_2 bold ui-title">{{ item.title }}</div>
|
||||
<div class="ui-product-num">X {{ item.num }}</div>
|
||||
<div class="bold text-right ui-total-price">¥{{ item.price_final / 100 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-fbc font_28 ui-pt-24">
|
||||
<div></div>
|
||||
<div class="f-fcr">
|
||||
<div v-if="item.status != 6" class="ui-state-btn f-fcc color3" @click.stop="jumpPath('', '')">申请退货</div>
|
||||
<!-- <div v-if="item.status == 6" class="ui-state-btn f-fcc color3" @click.stop="jumpReturn('returnGoods', item.id)">申请退货</div>-->
|
||||
<!-- <div v-if="item.status == 3" class="ui-state-btn-v2 f-fcc colorBlue" @click.stop="jumpReturn('returnGoodsDetail', item.id)">退货详情</div>-->
|
||||
<div class="ui-state-btn f-fcc color3 ui-ml-20" @click.stop="jumpPath('leaseShopDetail', item.spu_id)">再次购买</div>
|
||||
<div v-if="item.express_status == 4" class="ui-again-buy-btn f-fcc colorF ui-ml-20" @click.stop="signFor(item, index)">确认收货</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onActivated, onMounted, ref } from 'vue';
|
||||
import { showConfirmDialog, showLoadingToast, showToast } from 'vant';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
import { contactService } from '@/plugins/public';
|
||||
import router from '@/router';
|
||||
|
||||
defineOptions({ name: 'LeaseShopOrderList' });
|
||||
|
||||
const loadingState = ref<any>(false); // 页面数据加载完成判断
|
||||
const list = ref<any[]>([]); // 数据存储
|
||||
const noMore = ref(false); // 没有更多数据
|
||||
const refreshing = ref(false); // 上拉刷新false表示加载完成
|
||||
const finished = ref(false); // true表示数据全部加载完成
|
||||
const loading = ref(false); // false表示数据加载完成
|
||||
const page = ref(1); // 数据分页
|
||||
|
||||
const scrollValue = ref(0); // 记录页面列表的滚动距离
|
||||
const scrollDistance = ref<any>(null);
|
||||
|
||||
// 获取订单列表
|
||||
const getList = () => {
|
||||
requestGo({ url: `/h5/v2/shop/rental/order/list?page=${page.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
console.log(result, '8888');
|
||||
loadingState.value = true;
|
||||
if (list.value.length === 0 || page.value === 1) {
|
||||
list.value = result.data;
|
||||
} else if (list.value.length >= 15) {
|
||||
result.data.forEach((item) => {
|
||||
list.value.push(item);
|
||||
});
|
||||
}
|
||||
refreshing.value = false;
|
||||
loading.value = false;
|
||||
if (list.value.length < 15 || result.data.length < 15) {
|
||||
finished.value = true;
|
||||
noMore.value = true;
|
||||
}
|
||||
page.value++;
|
||||
})
|
||||
.catch((err) => {
|
||||
loadingState.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 签收商品
|
||||
const signFor = (e, index) => {
|
||||
showConfirmDialog({
|
||||
title: '温馨提示',
|
||||
message: `是否确认签收?`,
|
||||
})
|
||||
.then(() => {
|
||||
showLoadingToast('');
|
||||
requestGo({ url: `h5/v2/shop/rental/express/sign/${e.express_id}`, method: 'post' })
|
||||
.then(() => {
|
||||
showToast('签收成功');
|
||||
list.value[index].express_status = 5;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
// on cancel
|
||||
});
|
||||
};
|
||||
|
||||
// 上拉初始化数据
|
||||
const onRefresh = () => {
|
||||
loadingState.value = false;
|
||||
list.value = [];
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
finished.value = false;
|
||||
loading.value = true;
|
||||
getList();
|
||||
};
|
||||
|
||||
// const jumpReturn = (url, id) => {
|
||||
// if (id == 0) {
|
||||
// showToast('该商品已经下架');
|
||||
// return;
|
||||
// }
|
||||
// router.push({
|
||||
// name: url,
|
||||
// params: { id },
|
||||
// query: { type: '0', path: 'leaseShopOrderList' },
|
||||
// });
|
||||
// };
|
||||
|
||||
const jumpPath = (url, id) => {
|
||||
if (!url) {
|
||||
showConfirmDialog({
|
||||
title: '退款申请',
|
||||
message: `申请退款需联系客服操作`,
|
||||
})
|
||||
.then(() => {
|
||||
contactService();
|
||||
})
|
||||
.catch(() => {
|
||||
// on cancel
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (id == 0) {
|
||||
showToast('该商品已经下架');
|
||||
return;
|
||||
}
|
||||
router.push({
|
||||
name: url,
|
||||
params: { id },
|
||||
});
|
||||
};
|
||||
|
||||
// 监听页面滚动距离
|
||||
const handleScroll = (event) => {
|
||||
scrollValue.value = event.target.scrollTop;
|
||||
};
|
||||
|
||||
onActivated(() => {
|
||||
// 赋值离开时的滚动距离
|
||||
scrollDistance.value.scrollTop = scrollValue.value;
|
||||
// 如果是发起了退货申请或者取消了退货申请,相对应的列表申请退货按钮改变
|
||||
if (list.value && list.value.length > 0) {
|
||||
if (localStorage.getItem('refundGoods')) {
|
||||
let refundGoods = localStorage.getItem('refundGoods') as any;
|
||||
let state = refundGoods.split(',')[0];
|
||||
let orderId = refundGoods.split(',')[1];
|
||||
list.value.forEach((item) => {
|
||||
if (item.id == orderId) {
|
||||
if (state == 0) {
|
||||
item.status = 6;
|
||||
} else {
|
||||
item.status = 3;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
localStorage.removeItem('refundGoods');
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ui-leaseShopOrderList {
|
||||
background: #f8f8f8;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.ui-no-data-icon {
|
||||
width: px2rem(300);
|
||||
height: px2rem(164);
|
||||
display: block;
|
||||
margin: 25vh auto px2rem(20) auto;
|
||||
}
|
||||
|
||||
.ui-m-inf {
|
||||
padding: px2rem(30) px2rem(30) px2rem(200) px2rem(30);
|
||||
|
||||
.ui-inf-box {
|
||||
padding: px2rem(24);
|
||||
margin-bottom: px2rem(20);
|
||||
background: #ffffff;
|
||||
border-radius: px2rem(16);
|
||||
box-sizing: border-box;
|
||||
|
||||
.ui-m-avt-lst {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
.ui-pic {
|
||||
width: px2rem(120);
|
||||
height: px2rem(120);
|
||||
border: px2rem(2) solid #f8f8f8;
|
||||
display: block;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
border-radius: px2rem(8);
|
||||
margin-right: px2rem(24);
|
||||
}
|
||||
|
||||
.ui-m-lst-ri {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.ui-title {
|
||||
max-width: px2rem(320);
|
||||
line-height: px2rem(38);
|
||||
}
|
||||
|
||||
.ui-product-num {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: px2rem(-2);
|
||||
}
|
||||
|
||||
.ui-total-price {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: px2rem(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-separate-line {
|
||||
width: 100%;
|
||||
padding: 0 px2rem(24);
|
||||
margin: px2rem(26) 0 px2rem(32) px2rem(-24);
|
||||
height: px2rem(2);
|
||||
background: #eaeaea;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-again-buy-btn {
|
||||
width: px2rem(148);
|
||||
height: px2rem(52);
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #2a63b2;
|
||||
background: #2a63b2;
|
||||
}
|
||||
|
||||
.ui-state-btn,
|
||||
.ui-state-btn-v2 {
|
||||
width: px2rem(148);
|
||||
height: px2rem(52);
|
||||
border-radius: px2rem(8);
|
||||
border: px2rem(2) solid #d8d8d8;
|
||||
}
|
||||
|
||||
.ui-state-btn-v2 {
|
||||
border: px2rem(2) solid #2a63b2;
|
||||
}
|
||||
|
||||
.ui-no-more {
|
||||
margin-top: px2rem(40);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
698
src/views/subDir/newTest.vue
Normal file
698
src/views/subDir/newTest.vue
Normal file
@ -0,0 +1,698 @@
|
||||
<template>
|
||||
<div ref="agentHome" class="ui-agentHome">
|
||||
<div ref="topBox" class="ui-top-box">
|
||||
<div class="ui-relative ui-pt-16 ui-pb-20">
|
||||
<img class="ui-search-icon" src="https://image.fulllinkai.com/202405/13/629916bd281b7afa1a61ed099db182cf.png" alt="" />
|
||||
<div class="ui-pr-28 ui-pl-28" @click="jumpPath('shopSearch', {})">
|
||||
<van-field readonly class="ui-nutrient-input font_28 color3" placeholder="搜索商品" />
|
||||
</div>
|
||||
<div class="ui-search-right font_26">搜索</div>
|
||||
</div>
|
||||
<div class="ui-pl-28 ui-pr-28 ui-advertising">
|
||||
<van-swipe :autoplay="3000" lazy-render>
|
||||
<van-swipe-item v-for="(item, index) in bannerList" :key="index" class="ui-relative" @click.stop="jumpPath('banner', { id: item.shop_id })">
|
||||
<img class="ui-pics-item" :src="item.icon" alt="" />
|
||||
<div class="ui-mask"></div>
|
||||
</van-swipe-item>
|
||||
</van-swipe>
|
||||
</div>
|
||||
<div class="ui-type-pos ui-pt-24">
|
||||
<div class="ui-type-select ui-pb-12">
|
||||
<div v-for="(item, index) in typeList" :key="index" class="ui-pr-40 text-center" @click="changeType(item.id, index)">
|
||||
<!-- <img class="ui-type-pic" :src="item.icon" alt="" :class="typeIndex == index ? 'ui-type-pic-select' : ''" />-->
|
||||
<div class="ui-type-name font_28" :class="typeIndex == index ? 'ui-type-name-select font_32' : ''">{{ item.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-placeholder"></div>
|
||||
<div class="ui-tree-select" :style="{ height: treeSelectHeight }">
|
||||
<div style="padding: 1px"></div>
|
||||
<!-- <div class="ui-sidebar">-->
|
||||
<!-- <div v-for="(item, index) in typeList" :key="index" class="font_26 color3 ui-sidebar-item ui-relative" :class="typeIndex == index ? 'ui-sidebar-item-select bold' : ''" @click="changeType(item.id, index)">-->
|
||||
<!-- {{ item.name }}-->
|
||||
<!-- <div v-if="typeIndex + 1 == index" class="ui-sidebar-item-select-next"></div>-->
|
||||
<!-- <div v-if="typeIndex + 1 == typeList.length" class="ui-sidebar-item-select-not"></div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- <div class="ui-type-pos">-->
|
||||
<!-- <div class="ui-type-select ui-pb-12">-->
|
||||
<!-- <div v-for="(item, index) in typeList" :key="index" class="ui-pr-32" @click="changeType(item.id, index)">-->
|
||||
<!-- <!– <img class="ui-type-pic" :src="item.icon" alt="" :class="typeIndex == index ? 'ui-type-pic-select' : ''" />–>-->
|
||||
<!-- <div class="ui-type-name font_26 color3" :class="typeIndex == index ? 'ui-type-name-select' : ''">{{ item.name }}</div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<div ref="productList" class="ui-tab-content" @scroll="handleScroll">
|
||||
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
|
||||
<van-list v-model:loading="loading" :finished="finished" @load="getList">
|
||||
<div v-if="loadingState && list.length == 0">
|
||||
<img class="ui-no-data-icon" src="https://image.fulllinkai.com/202406/03/3e513a3dac7b6d19d5c0bfc73a7d2c4c.png" alt="" />
|
||||
<div class="color6 font_30 text-center">暂无数据</div>
|
||||
</div>
|
||||
<div v-else class="ui-product-box">
|
||||
<div class="ui-product-list">
|
||||
<div v-for="(item, index) in list" :key="index" @click="jumpPath('shopDetail', { id: item.id })">
|
||||
<!-- <div v-if="item.typeTitle" ref="typeTitle" class="font_28 bold color3 ui-pl-28 ui-pb-20 ui-pt-16">{{ item.typeTitle }}</div>-->
|
||||
<div v-if="item.typeTitle" ref="typeTitle" :key="item.typeTitle"></div>
|
||||
<div class="ui-product-item">
|
||||
<div style="display: flex">
|
||||
<img class="ui-product-pic" :src="item.pic || item.icon" alt="" />
|
||||
<div class="ui-title-box">
|
||||
<div class="font_30 ellipsis_2 ui-product-title">{{ item.title }}</div>
|
||||
<div class="f-fbc">
|
||||
<div class="ui-buy-data">
|
||||
<div v-if="item.price == '0.00' || item.price == '0'" class="font_34 bold ui-price">免费</div>
|
||||
<div v-else class="font_36 bold ui-price-v2"><span class="font_24 ui-price-symbol">¥</span>{{ item.price }}</div>
|
||||
</div>
|
||||
<div class="ui-buy-btn font_24 f-fcc colorF">立即购买</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onActivated, onDeactivated } from 'vue';
|
||||
import router from '@/router';
|
||||
import requestGo from '@/utils/requestGo';
|
||||
import { weXinShare } from '@/plugins/wxShare';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
|
||||
defineOptions({ name: 'AgentHome' });
|
||||
|
||||
const agentHome = ref<any>(null);
|
||||
const userStore = useUserStore() as any;
|
||||
const topBox = ref<any>(null);
|
||||
|
||||
const typeList = ref<any[]>([]);
|
||||
const typeIndex = ref(0);
|
||||
const treeSelectHeight = ref<any>('100vh');
|
||||
|
||||
const bannerList = ref<any[]>([]);
|
||||
|
||||
const loadingState = ref<any>(false); // 页面数据加载完成判断
|
||||
const list = ref<any[]>([]); // 数据存储
|
||||
const refreshing = ref(false); // 上拉刷新false表示加载完成
|
||||
const finished = ref(true); // true表示数据全部加载完成
|
||||
const loading = ref(false); // false表示数据加载完成
|
||||
const page = ref(1); // 数据分页
|
||||
|
||||
const scrollValue = ref(0); // 记录页面列表的滚动距离
|
||||
const productList = ref<any>(null);
|
||||
const typeTitle = ref<any>(null);
|
||||
const scrollLoading = ref(false);
|
||||
const anchors = ref<any[]>([]); // 所有的分类标题位置
|
||||
|
||||
// 获取商品列表
|
||||
const getList = () => {
|
||||
requestGo({ url: `/h5/v2/shop/common/spu/list?page=${page.value}`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
if (result.total_pages < page.value) {
|
||||
return;
|
||||
}
|
||||
if (result.data && result.data.length > 0) {
|
||||
result.data.forEach((item) => {
|
||||
item.types = item.category_ids.split(',')[0];
|
||||
});
|
||||
}
|
||||
|
||||
if (list.value.length === 0 || page.value === 1) {
|
||||
list.value = result.data;
|
||||
list.value.map((item) => {
|
||||
if (item.id == 110) {
|
||||
getSPSkuPrice(item.skuid);
|
||||
}
|
||||
});
|
||||
} else if (list.value.length >= 15) {
|
||||
result.data.forEach((item) => {
|
||||
list.value.push(item);
|
||||
});
|
||||
result.value.map((item) => {
|
||||
if (item.id == 110) {
|
||||
getSPSkuPrice(item.skuid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refreshing.value = false;
|
||||
loading.value = false;
|
||||
if (list.value.length < 15 || result.data.length < 15) {
|
||||
finished.value = true;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
// 赋值列表归属类型
|
||||
typeList.value.forEach((i) => {
|
||||
list.value.forEach((item) => {
|
||||
if (item.types == i.id) {
|
||||
item.typeName = i.name;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 列表相同类型增加标题
|
||||
list.value.forEach((item, index) => {
|
||||
if (index == 0) {
|
||||
item.typeTitle = item.typeName;
|
||||
}
|
||||
if (index + 1 != list.value.length && item.typeName != list.value[index + 1].typeName) {
|
||||
list.value[index + 1].typeTitle = list.value[index + 1].typeName;
|
||||
}
|
||||
});
|
||||
|
||||
page.value++;
|
||||
if (!loadingState.value) {
|
||||
weXinShare('https://image.fulllinkai.com/202310/28/88e931a50ec0a8094fb46191b389457e.png', `https://health.ufutx.com/store/#/agentHome?from_user_id=${userStore.userID}&from_type=rt_home`, '友福商城', '邀请您进入友福商城');
|
||||
}
|
||||
loadingState.value = true;
|
||||
anchors.value = [];
|
||||
setTimeout(() => {
|
||||
for (let i = 0; i < typeList.value.length; i++) {
|
||||
let status = false;
|
||||
console.log(typeTitle.value, 'typeTitle.value=');
|
||||
typeTitle.value.map((item, index) => {
|
||||
console.log(item.__vnode.key, 'item====333');
|
||||
if (!status && typeList.value[i].name == item.__vnode.key) {
|
||||
status = true;
|
||||
anchors.value.push(item.offsetTop);
|
||||
} else if (!status && index == typeTitle.value.length - 1) {
|
||||
anchors.value.push('');
|
||||
}
|
||||
});
|
||||
// console.log(typeTitle.value[i].textContent, 'ff');
|
||||
// if (typeTitle.value[i]) {
|
||||
// anchors.value.push(typeTitle.value[i].offsetTop);
|
||||
// } else {
|
||||
// anchors.value.push(typeTitle.value[i - 1].offsetTop);
|
||||
// }
|
||||
}
|
||||
console.log(anchors.value, '8888');
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
loadingState.value = true;
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
// 获取特殊价格(月饼)
|
||||
const getSPSkuPrice = (skuid) => {
|
||||
requestGo({ url: `/h5/v2/shop/common/sku/prepay/${skuid}/1/1`, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
console.log(result, '77777');
|
||||
list.value = list.value.map((item) => {
|
||||
console.log(item.id, 'item.id');
|
||||
if (item.id == 110) {
|
||||
item.price = result.price;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
console.log(list, 'list==');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取分类列表
|
||||
const getType = () => {
|
||||
requestGo({ url: `/h5/v2/shop/common/category/list`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
typeList.value = result;
|
||||
getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取广告位数据
|
||||
const getBanner = () => {
|
||||
requestGo({ url: `/app/user/carousel/list?place=SHOP_HOME`, hideLoading: true, method: 'get' })
|
||||
.then((res) => {
|
||||
const result = res.data;
|
||||
bannerList.value = result.filter((item) => {
|
||||
return !item.program;
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const jumpPath = (url: string, e: any) => {
|
||||
if (url == 'banner') {
|
||||
console.log('e', e);
|
||||
if (e) {
|
||||
router.push({
|
||||
name: 'shopDetail',
|
||||
params: e,
|
||||
});
|
||||
} else {
|
||||
location.href = e.url;
|
||||
}
|
||||
} else {
|
||||
router.push({
|
||||
name: url,
|
||||
params: e,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取点击类型跳转至相对应位置
|
||||
const changeType = (id, idx) => {
|
||||
console.log('444===');
|
||||
if (scrollLoading.value) {
|
||||
return;
|
||||
}
|
||||
console.log(id, idx, '666');
|
||||
typeIndex.value = idx;
|
||||
let state = false;
|
||||
if (list.value && list.value.length > 0) {
|
||||
list.value.forEach((item) => {
|
||||
console.log(item.types, id, '3333===');
|
||||
if (!state && item.types == id) {
|
||||
console.log('3333===');
|
||||
typeTitle.value.map((itemV2) => {
|
||||
console.log(item.typeName, itemV2, '3333=gggg==');
|
||||
console.log(item.typeName, itemV2.__vnode.key, '3333=gggg==');
|
||||
if (!state && item.typeName == itemV2.__vnode.key) {
|
||||
state = true;
|
||||
console.log(itemV2.offsetTop, 'itemV2.offsetTop');
|
||||
scrollValue.value = itemV2.offsetTop;
|
||||
console.log(scrollValue.value, 'scrollValue');
|
||||
productList.value.scrollTop = scrollValue.value - 16;
|
||||
console.log(productList.value.scrollTop, 'productList.value.scrollTop=');
|
||||
}
|
||||
});
|
||||
// state = true;
|
||||
// scrollValue.value = typeTitle.value[idx].offsetTop;
|
||||
// productList.value.scrollTop = scrollValue.value - 16;
|
||||
}
|
||||
});
|
||||
console.log('ggg=');
|
||||
}
|
||||
};
|
||||
|
||||
// 监听列表滚动距离定位相对应类型下标
|
||||
const handleScroll = (event) => {
|
||||
scrollLoading.value = true;
|
||||
anchors.value.findIndex((e, index) => {
|
||||
if (e && event.target.scrollTop + 80 >= e) {
|
||||
typeIndex.value = index;
|
||||
setTimeout(() => {
|
||||
scrollLoading.value = false;
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 上拉初始化数据
|
||||
const onRefresh = () => {
|
||||
page.value = 1;
|
||||
list.value = [];
|
||||
finished.value = false;
|
||||
loading.value = true;
|
||||
getList();
|
||||
};
|
||||
|
||||
onActivated(() => {
|
||||
// 赋值离开时的滚动距离
|
||||
productList.value.scrollTop = scrollValue.value;
|
||||
});
|
||||
|
||||
onDeactivated(() => {});
|
||||
|
||||
onMounted(() => {
|
||||
getType();
|
||||
getBanner();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ui-agentHome {
|
||||
.van-popup {
|
||||
overflow-y: initial;
|
||||
}
|
||||
|
||||
.van-swipe__indicators {
|
||||
//left: px2rem(262);
|
||||
bottom: px2rem(10);
|
||||
}
|
||||
|
||||
.van-swipe__indicator--active {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.van-swipe__indicator {
|
||||
width: px2rem(20);
|
||||
height: px2rem(8);
|
||||
border-radius: px2rem(20);
|
||||
}
|
||||
.van-field {
|
||||
height: px2rem(48);
|
||||
line-height: px2rem(48);
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.ui-agentHome {
|
||||
background: #ffffff;
|
||||
overflow: hidden;
|
||||
max-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-top-box {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
background: #ffffff;
|
||||
|
||||
.ui-search-icon {
|
||||
width: px2rem(36);
|
||||
height: px2rem(36);
|
||||
position: absolute;
|
||||
left: px2rem(52);
|
||||
top: px2rem(32);
|
||||
z-index: 2;
|
||||
}
|
||||
.ui-search-right {
|
||||
position: absolute;
|
||||
right: px2rem(52);
|
||||
top: px2rem(32);
|
||||
padding-left: px2rem(20);
|
||||
border-left: px2rem(1) solid #dddddd; /* 设置左边框的宽度 */
|
||||
margin-left: auto; /* 左边距设置为自动 */
|
||||
margin-right: auto; /* 右边距也设置为自动以使元素水平居中 */
|
||||
}
|
||||
|
||||
.ui-nutrient-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 px2rem(72);
|
||||
height: px2rem(68);
|
||||
//border: px2rem(2) solid #2a63b2;
|
||||
border-radius: px2rem(200);
|
||||
}
|
||||
|
||||
.ui-search-cancel-icon {
|
||||
width: px2rem(28);
|
||||
height: px2rem(28);
|
||||
position: absolute;
|
||||
right: px2rem(60);
|
||||
top: px2rem(50);
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
.ui-advertising {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: px2rem(100);
|
||||
padding-top: 0;
|
||||
padding-bottom: px2rem(20);
|
||||
z-index: 33;
|
||||
overflow: hidden;
|
||||
transform: translateY(0);
|
||||
background: #ffffff;
|
||||
//padding-bottom: px2rem(124);
|
||||
}
|
||||
|
||||
.ui-pics-item {
|
||||
width: px2rem(686);
|
||||
height: px2rem(200);
|
||||
border-radius: px2rem(32);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ui-type-pos {
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
height: px2rem(60);
|
||||
top: px2rem(320);
|
||||
background: #f8f8f8;
|
||||
border-radius: px2rem(24) px2rem(24) 0 0;
|
||||
z-index: 44;
|
||||
}
|
||||
.ui-type-select {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
margin: 0 px2rem(24);
|
||||
|
||||
.ui-type-pic,
|
||||
.ui-type-pic-select {
|
||||
width: px2rem(80);
|
||||
height: px2rem(80);
|
||||
border-radius: px2rem(16);
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ui-type-pic-select {
|
||||
width: px2rem(76);
|
||||
height: px2rem(76);
|
||||
border: px2rem(4) solid #2a63b2;
|
||||
}
|
||||
|
||||
.ui-type-name,
|
||||
.ui-type-name-select {
|
||||
padding: px2rem(4) px2rem(14);
|
||||
//border-radius: px2rem(8);
|
||||
//background: #ffffff;
|
||||
//margin-top: px2rem(8);
|
||||
color: #b2b3b5;
|
||||
}
|
||||
|
||||
.ui-type-name-select {
|
||||
color: #2a63b2;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-type-select::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-placeholder {
|
||||
width: 100%;
|
||||
height: px2rem(260);
|
||||
}
|
||||
|
||||
.ui-tree-select {
|
||||
width: 100vw;
|
||||
background: linear-gradient(180deg, #fafafa 0%, #ffffff 100%);
|
||||
|
||||
position: relative;
|
||||
//overflow-y: scroll;
|
||||
//display: flex;
|
||||
|
||||
//position: absolute;
|
||||
//top: px2rem(160);
|
||||
//height: px2rem(800);
|
||||
//z-index: 100;
|
||||
.ui-placeholder-v2 {
|
||||
width: 100%;
|
||||
height: px2rem(160);
|
||||
}
|
||||
|
||||
.ui-type-select {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
overflow: hidden;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
margin: 0 px2rem(24);
|
||||
|
||||
.ui-type-pic,
|
||||
.ui-type-pic-select {
|
||||
width: px2rem(80);
|
||||
height: px2rem(80);
|
||||
border-radius: px2rem(16);
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ui-type-pic-select {
|
||||
width: px2rem(76);
|
||||
height: px2rem(76);
|
||||
border: px2rem(4) solid #2a63b2;
|
||||
}
|
||||
|
||||
.ui-type-name,
|
||||
.ui-type-name-select {
|
||||
padding: px2rem(4) px2rem(14);
|
||||
//border-radius: px2rem(8);
|
||||
//background: #ffffff;
|
||||
margin-top: px2rem(8);
|
||||
}
|
||||
|
||||
.ui-type-name-select {
|
||||
color: #2a63b2;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.ui-type-select::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
//.ui-sidebar {
|
||||
// width: px2rem(168);
|
||||
// padding-bottom: px2rem(420);
|
||||
// background: #f4f4f4;
|
||||
// overflow-y: auto;
|
||||
// -webkit-overflow-scrolling: touch;
|
||||
// text-align: center;
|
||||
//
|
||||
// .ui-sidebar-item {
|
||||
// background: #f4f4f4;
|
||||
// padding: px2rem(28) 0;
|
||||
// }
|
||||
//
|
||||
// .ui-sidebar-item-select {
|
||||
// color: #2a63b2;
|
||||
// background: #ffffff;
|
||||
// }
|
||||
//
|
||||
// .ui-sidebar-item-select:before {
|
||||
// width: px2rem(6);
|
||||
// height: px2rem(48);
|
||||
// position: absolute;
|
||||
// top: 50%;
|
||||
// left: 0;
|
||||
// transform: translateY(-50%);
|
||||
// background: #2a63b2;
|
||||
// border-radius: px2rem(30);
|
||||
// content: '';
|
||||
// }
|
||||
//
|
||||
// .ui-sidebar-item-select-next,
|
||||
// .ui-sidebar-item-select-not {
|
||||
// width: px2rem(16);
|
||||
// height: px2rem(16);
|
||||
// position: absolute;
|
||||
// right: 0;
|
||||
// top: 0;
|
||||
// background: radial-gradient(circle at left bottom, transparent 0, transparent px2rem(16), #ffffff px2rem(16));
|
||||
// z-index: 2;
|
||||
// }
|
||||
//
|
||||
// .ui-sidebar-item-select-not {
|
||||
// right: 0;
|
||||
// top: initial;
|
||||
// bottom: px2rem(-16);
|
||||
// }
|
||||
//}
|
||||
|
||||
.ui-tab-content {
|
||||
position: absolute;
|
||||
top: px2rem(160);
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100%;
|
||||
padding-bottom: px2rem(240);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-product-list {
|
||||
padding: 0 px2rem(20) px2rem(630);
|
||||
background: #f8f8f8;
|
||||
//overflow-y: auto;
|
||||
.ui-product-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
height: px2rem(260);
|
||||
margin-bottom: px2rem(20);
|
||||
padding: px2rem(20);
|
||||
border-radius: px2rem(32);
|
||||
background: #ffffff;
|
||||
.ui-product-pic {
|
||||
width: px2rem(266);
|
||||
height: px2rem(266);
|
||||
border-radius: px2rem(32);
|
||||
margin-right: px2rem(20);
|
||||
display: block;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
vertical-align: top;
|
||||
}
|
||||
.ui-title-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.ui-product-title {
|
||||
width: px2rem(390);
|
||||
max-width: px2rem(390);
|
||||
color: #0e0e0e;
|
||||
}
|
||||
|
||||
.ui-buy-data {
|
||||
//position: absolute;
|
||||
//bottom: px2rem(0);
|
||||
|
||||
.ui-price-symbol {
|
||||
margin-right: px2rem(4);
|
||||
}
|
||||
|
||||
.ui-price,
|
||||
.ui-price-v2 {
|
||||
position: relative;
|
||||
bottom: px2rem(-2);
|
||||
color: #cc352f;
|
||||
}
|
||||
|
||||
.ui-price-v2 {
|
||||
bottom: px2rem(-6);
|
||||
}
|
||||
}
|
||||
|
||||
.ui-buy-btn {
|
||||
width: px2rem(96);
|
||||
height: px2rem(34);
|
||||
background: #2a63b2;
|
||||
border-radius: px2rem(56);
|
||||
padding: px2rem(12) px2rem(20);
|
||||
//position: absolute;
|
||||
//bottom: 0;
|
||||
//right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-no-data-icon {
|
||||
width: px2rem(300);
|
||||
height: px2rem(164);
|
||||
display: block;
|
||||
margin: 11vh auto px2rem(20) auto;
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user