Compare commits
No commits in common. 'master' and 'dev' have entirely different histories.
226 changed files with 3609 additions and 51640 deletions
@ -1,3 +0,0 @@ |
|||||
{ |
|
||||
"presets": ["@babel/preset-env"] |
|
||||
} |
|
||||
@ -1,25 +1,5 @@ |
|||||
NODE_ENV = 'development' |
ENV='development' |
||||
|
# base api |
||||
# api请求地址 |
VITE_APP_BASE_URL = 'https://evote.truescloud.com' |
||||
VITE_APP_BASE_URL='http://shop.zeyan.wang/index.php/api/' |
VITE_APP_BASE_PRE = '/dev-api' |
||||
|
VITE_APP_BASE_NAME = 'POS' |
||||
# 图片服务器地址 |
|
||||
VITE_IMG_DOMAIN='http://shop.zeyan.wang/' |
|
||||
|
|
||||
# 站点id 仅在编译为小程序时生效 |
|
||||
VITE_SITE_ID = '100000' |
|
||||
|
|
||||
# 本地存储时token的参数名 |
|
||||
VITE_REQUEST_STORAGE_TOKEN_KEY='wapToken' |
|
||||
|
|
||||
# 请求时header中token的参数名 |
|
||||
VITE_REQUEST_HEADER_TOKEN_KEY='token' |
|
||||
|
|
||||
# 请求时header中站点的参数名 |
|
||||
VITE_REQUEST_HEADER_SITEID_KEY='site-id' |
|
||||
|
|
||||
# 请求时header中来源场景的参数名 |
|
||||
VITE_REQUEST_HEADER_CHANNEL_KEY='channel' |
|
||||
|
|
||||
# 应用版本 |
|
||||
VITE_APP_VERSION='1.0.1' |
|
||||
|
|||||
@ -0,0 +1,3 @@ |
|||||
|
dist |
||||
|
node_modules |
||||
|
uni_modules |
||||
@ -0,0 +1,146 @@ |
|||||
|
// @see https://eslint.bootcss.com/docs/rules/ |
||||
|
|
||||
|
module.exports = { |
||||
|
env: { |
||||
|
browser: true, |
||||
|
es2021: true, |
||||
|
node: true |
||||
|
}, |
||||
|
globals: { |
||||
|
NodeJS: 'readonly' |
||||
|
}, |
||||
|
/* 指定如何解析语法 */ |
||||
|
parser: 'vue-eslint-parser', |
||||
|
/** 优先级低于 parse 的语法解析配置 */ |
||||
|
parserOptions: { |
||||
|
ecmaVersion: 'latest', |
||||
|
sourceType: 'module', |
||||
|
parser: '@typescript-eslint/parser', |
||||
|
jsxPragma: 'React', |
||||
|
ecmaFeatures: { |
||||
|
jsx: true |
||||
|
} |
||||
|
}, |
||||
|
/* 继承已有的规则 */ |
||||
|
extends: ['eslint:recommended', 'plugin:vue/vue3-essential', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], |
||||
|
plugins: ['vue', '@typescript-eslint'], |
||||
|
overrides: [ |
||||
|
{ |
||||
|
files: ['*.ts', '*.tsx', '*.vue'], |
||||
|
rules: { |
||||
|
'no-undef': 0 |
||||
|
} |
||||
|
} |
||||
|
], |
||||
|
/* |
||||
|
* 'off' 或 0 ==> 关闭规则 |
||||
|
* 'warn' 或 1 ==> 打开的规则作为警告(不影响代码执行) |
||||
|
* 'error' 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) |
||||
|
*/ |
||||
|
rules: { |
||||
|
// typeScript (https://typescript-eslint.io/rules) |
||||
|
'@typescript-eslint/no-unused-vars': [2, { argsIgnorePattern: '^_' }], // 禁止定义未使用的变量 |
||||
|
'@typescript-eslint/prefer-ts-expect-error': 2, // 禁止使用 @ts-ignore |
||||
|
'@typescript-eslint/no-explicit-any': 0, // 禁止使用 any 类型 |
||||
|
'@typescript-eslint/no-non-null-assertion': 0, |
||||
|
'@typescript-eslint/no-namespace': 0, // 禁止使用自定义 TypeScript 模块和命名空间。 |
||||
|
'@typescript-eslint/semi': 0, |
||||
|
'no-prototype-builtins': 0, // 可以使用obj.hasOwnProperty() |
||||
|
'@typescript-eslint/no-var-requires': 0, // 不允许在import 中使用require |
||||
|
'@typescript-eslint/no-empty-function': 2, // 关闭空方法检查 |
||||
|
// eslint-plugin-vue (https://eslint.vuejs.org/rules/) |
||||
|
'vue/multi-word-component-names': 0, // 要求组件名称始终为 “-” 链接的单词 |
||||
|
'vue/script-setup-uses-vars': 2, // 防止<script setup>使用的变量<template>被标记为未使用 |
||||
|
'vue/no-mutating-props': 0, // 不允许组件 prop的改变 |
||||
|
'vue/no-v-html': 0, // 禁止使用 v-html |
||||
|
'vue/no-setup-props-destructure': 0, // 禁止 props 解构传递给 setup |
||||
|
'vue/no-v-model-argument': 0, // 不允许添加要在 v-model 自定义组件中使用的参数 |
||||
|
'vue/component-definition-name-casing': [2, 'PascalCase'], // 强制使用组件定义名称的特定大小写 PascalCase | kebab-case |
||||
|
'vue/attribute-hyphenation': [2, 'always', { ignore: [] }], // 对模板中的自定义组件强制实施属性命名样式 |
||||
|
'vue/no-dupe-keys': [2, { groups: [] }], // 不允许重复字段名称 |
||||
|
'vue/no-dupe-v-else-if': 2, // 不允许 / v-else-if 链中的 v-if 重复条件 |
||||
|
'vue/no-duplicate-attributes': 2, // 禁止属性重复 |
||||
|
'vue/no-ref-as-operand': 2, // 使用ref对象必须.value |
||||
|
'vue/first-attribute-linebreak': [ |
||||
|
2, |
||||
|
{ |
||||
|
singleline: 'ignore', |
||||
|
multiline: 'below' |
||||
|
} |
||||
|
], // 强制设置第一个属性的位置 |
||||
|
|
||||
|
'@typescript-eslint/no-this-alias': [ |
||||
|
'warn', |
||||
|
{ |
||||
|
allowDestructuring: false, // Disallow `const { props, state } = this`; true by default |
||||
|
allowedNames: ['_this'] // this的別名可以为_this |
||||
|
} |
||||
|
], |
||||
|
// eslint(https://eslint.bootcss.com/docs/rules/) |
||||
|
// 'object-curly-spacing': 0, // 在大括号内强制执行一致的间距 |
||||
|
'no-unexpected-multiline': 2, // 禁止空余的多行 |
||||
|
'no-await-in-loop': 2, // 该规则不允许在循环体中使用 await |
||||
|
'no-dupe-else-if': 2, // 禁止 if-else-if 链中的重复条件 |
||||
|
'no-const-assign': 2, // 禁止重新分配 const 变量 |
||||
|
'no-dupe-keys': 2, // 禁止对象字面量中的重复键 |
||||
|
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行 |
||||
|
'no-unused-vars': 0, // 禁止未使用的变量 |
||||
|
'use-isnan': 2, // 检查 NaN 时需要调用 isNaN() |
||||
|
'valid-typeof': 2, // 强制将 typeof 表达式与有效字符串进行比较 |
||||
|
'no-var': 2, // 要求使用 let 或 const 而不是 var |
||||
|
'no-extra-semi': 2, // 禁止不必要的分号 |
||||
|
'no-multi-str': 2, // 禁止多行字符串 |
||||
|
'no-unused-labels': 2, // 禁止未使用的标签 |
||||
|
'array-bracket-newline': [2, 'consistent'], // 在打开数组括号之后和关闭数组括号之前强制换行 |
||||
|
eqeqeq: [2, 'smart'], // 必须使用全等 |
||||
|
'arrow-spacing': 2, // 在箭头函数中的箭头前后强制执行一致的间距 |
||||
|
'function-call-argument-newline': [2, 'consistent'], // 在函数调用的参数之间强制换行 |
||||
|
'no-undef': 2, // 禁止使用未声明的变量,除非在 /*global */ 注释中提及 |
||||
|
complexity: [2, 15], |
||||
|
indent: [2, 4, { SwitchCase: 1 }], |
||||
|
'valid-jsdoc': 0, //jsdoc规则 |
||||
|
'no-console': 0, |
||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, |
||||
|
'no-useless-escape': 0, // 禁止不必要的转义字符 |
||||
|
'@typescript-eslint/ban-types': 0, // 允许使用function 声明函数 |
||||
|
'prettier/prettier': [ |
||||
|
2, |
||||
|
{ |
||||
|
//在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x |
||||
|
arrowParens: 'always', |
||||
|
// 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false |
||||
|
bracketSameLine: false, |
||||
|
// 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) |
||||
|
bracketSpacing: true, |
||||
|
// 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) |
||||
|
embeddedLanguageFormatting: 'auto', |
||||
|
// 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) |
||||
|
htmlWhitespaceSensitivity: 'ignore', |
||||
|
// 一行最多多少个字符 |
||||
|
printWidth: 150, |
||||
|
// 超出打印宽度 (always | never | preserve ) |
||||
|
proseWrap: 'preserve', |
||||
|
// 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) |
||||
|
quoteProps: 'as-needed', |
||||
|
// 指定要使用的解析器,不需要写文件开头的 @prettier |
||||
|
requirePragma: false, |
||||
|
// 不需要自动在文件开头插入 @prettier |
||||
|
insertPragma: false, |
||||
|
// 最后不需要引号 |
||||
|
semi: false, |
||||
|
// 使用单引号 (true:单引号;false:双引号) |
||||
|
singleQuote: true, |
||||
|
// 缩进空格数,默认2个空格 |
||||
|
tabWidth: 4, |
||||
|
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none |
||||
|
trailingComma: 'none', |
||||
|
// 使用制表符而不是空格缩进行 |
||||
|
useTabs: false, |
||||
|
// Vue文件脚本和样式标签缩进 |
||||
|
vueIndentScriptAndStyle: false, |
||||
|
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>" |
||||
|
endOfLine: 'auto' |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
@ -1,22 +1,30 @@ |
|||||
# Logs |
.DS_Store |
||||
logs |
/node_modules |
||||
*.log |
/dist |
||||
|
|
||||
|
# local env files |
||||
|
.env.local |
||||
|
.env.*.local |
||||
|
|
||||
|
# Log files |
||||
npm-debug.log* |
npm-debug.log* |
||||
yarn-debug.log* |
yarn-debug.log* |
||||
yarn-error.log* |
yarn-error.log* |
||||
pnpm-debug.log* |
|
||||
lerna-debug.log* |
|
||||
|
|
||||
node_modules |
|
||||
.DS_Store |
|
||||
dist |
|
||||
*.local |
|
||||
|
|
||||
# Editor directories and files |
# Editor directories and files |
||||
|
.project |
||||
.idea |
.idea |
||||
|
.vscode |
||||
*.suo |
*.suo |
||||
*.ntvs* |
*.ntvs* |
||||
*.njsproj |
*.njsproj |
||||
*.sln |
*.sln |
||||
*.sw? |
*.sw* |
||||
|
|
||||
|
/unpackage |
||||
.hbuilderx |
.hbuilderx |
||||
|
|
||||
|
package-lock.josn |
||||
|
pnpm-lock.yaml |
||||
|
|
||||
|
/types/auto-imports.d.ts |
||||
@ -0,0 +1,4 @@ |
|||||
|
#!/usr/bin/env sh |
||||
|
. "$(dirname -- "$0")/_/husky.sh" |
||||
|
|
||||
|
pnpm run fix |
||||
@ -0,0 +1,8 @@ |
|||||
|
/dist/* |
||||
|
/html/* |
||||
|
.local |
||||
|
/node_modules/** |
||||
|
**/*.svg |
||||
|
**/*.sh |
||||
|
/public/* |
||||
|
/uni_modules/* |
||||
@ -0,0 +1,36 @@ |
|||||
|
module.exports = { |
||||
|
//在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x |
||||
|
arrowParens: 'always', |
||||
|
// 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false |
||||
|
bracketSameLine: false, |
||||
|
// 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) |
||||
|
bracketSpacing: true, |
||||
|
// 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) |
||||
|
embeddedLanguageFormatting: 'auto', |
||||
|
// 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) |
||||
|
htmlWhitespaceSensitivity: 'ignore', |
||||
|
// 一行最多多少个字符 |
||||
|
printWidth: 150, |
||||
|
// 超出打印宽度 (always | never | preserve ) |
||||
|
proseWrap: 'preserve', |
||||
|
// 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) |
||||
|
quoteProps: 'as-needed', |
||||
|
// 指定要使用的解析器,不需要写文件开头的 @prettier |
||||
|
requirePragma: false, |
||||
|
// 不需要自动在文件开头插入 @prettier |
||||
|
insertPragma: false, |
||||
|
// 最后不需要引号 |
||||
|
semi: false, |
||||
|
// 使用单引号 (true:单引号;false:双引号) |
||||
|
singleQuote: true, |
||||
|
// 缩进空格数,默认2个空格 |
||||
|
tabWidth: 4, |
||||
|
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none |
||||
|
trailingComma: 'none', |
||||
|
// 使用制表符而不是空格缩进行 |
||||
|
useTabs: false, |
||||
|
// Vue文件脚本和样式标签缩进 |
||||
|
vueIndentScriptAndStyle: false, |
||||
|
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>" |
||||
|
endOfLine: 'auto' |
||||
|
} |
||||
@ -1,2 +1,30 @@ |
|||||
# Election |
## 项目介绍 |
||||
|
|
||||
|
[uniapp-vue-vite-ts](https://gitee.com/lxxlalala/uniapp-vue-vite-ts) 是基于 Vue3 + Vite4+ TypeScript + uview-plus V3 + Pinia 等最新主流技术栈构建的uniapp前端模板。 |
||||
|
|
||||
|
| 环境 | 名称版本 | |
||||
|
| -------------------- | :----------------------------------------------------------- | |
||||
|
| **开发工具** | VSCode | |
||||
|
| **运行环境** | Node 16+ | |
||||
|
| **VSCode插件(必装)** | 1. `Vue Language Features (Volar) ` <br/>2. `TypeScript Vue Plugin (Volar) ` <br/>3. 禁用 Vetur <br/>4.ESLint <br/>5.Prettier - Code formatter | |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 项目启动 |
||||
|
|
||||
|
```bash |
||||
|
# 安装 pnpm |
||||
|
npm install pnpm -g |
||||
|
|
||||
|
# 安装依赖 |
||||
|
pnpm install |
||||
|
|
||||
|
# 启动运行 |
||||
|
pnpm run dev:h5 (或者查看package.json运行对应平台命令) |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
|
||||
|
## 项目文档 |
||||
|
|
||||
|
- [ESLint+Prettier+Husky 约束和统一前端代码规范](https://blog.csdn.net/qq_51091386/article/details/132099829) |
||||
|
|||||
@ -0,0 +1,85 @@ |
|||||
|
const fs = require('fs') |
||||
|
|
||||
|
const pagesStr = fs.readFileSync('./src/pages.json', 'utf-8'); |
||||
|
const pagesJson = JSON.parse(pagesStr); |
||||
|
// Pages页面
|
||||
|
const Pages = pagesJson.pages.map((i) => { |
||||
|
return { |
||||
|
type: 'Pages', |
||||
|
name: i.name, |
||||
|
path: `/${i.path}`, |
||||
|
title: i.style?.navigationBarTitleText |
||||
|
}; |
||||
|
}); |
||||
|
// 二级页面
|
||||
|
const subPages = pagesJson.subPackages.flatMap((i) => { |
||||
|
return i.pages.map((x) => { |
||||
|
return { |
||||
|
type: 'subPage', |
||||
|
name: x.name, |
||||
|
path: `/${i.root}/${x.path}`, |
||||
|
title: x.style?.navigationBarTitleText |
||||
|
}; |
||||
|
}); |
||||
|
}); |
||||
|
// 当前已有页面
|
||||
|
// const pages = [...Pages, ...subPages];
|
||||
|
// 当前已创建文件
|
||||
|
const filesList = fs.readdirSync('./src/pages'); |
||||
|
const filesSubList = fs.readdirSync('./src/subpackage/pages'); |
||||
|
|
||||
|
// 获取需要新增的页面 =>取差集
|
||||
|
let newPages = Pages.filter((i) => !filesList.includes(i.name)); |
||||
|
const newSubPages = subPages.filter((i) => !filesSubList.includes(i.name)); |
||||
|
|
||||
|
newPages = [...newPages, ...newSubPages] |
||||
|
|
||||
|
// 添加新路由
|
||||
|
function addPages(pages) { |
||||
|
for (const page of pages) { |
||||
|
// 待修改根据path 路径生成
|
||||
|
const { name, title, type } = page; |
||||
|
let dirPath = '' |
||||
|
switch (type) { |
||||
|
case 'Pages': |
||||
|
// 主包
|
||||
|
dirPath = `./src/pages/${name}`; |
||||
|
break; |
||||
|
case 'subPage': |
||||
|
// 分包
|
||||
|
dirPath = `./src/subpackage/pages/${name}`; |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
// if (name.toLowerCase().indexOf("list") != -1) {
|
||||
|
// console.log(22222222);
|
||||
|
|
||||
|
// } else {
|
||||
|
// console.log(33333333);
|
||||
|
// }
|
||||
|
|
||||
|
// return
|
||||
|
fs.mkdirSync(dirPath); |
||||
|
const filePath = `${dirPath}/${name}.vue`; |
||||
|
const createStream = fs.createWriteStream(filePath); |
||||
|
|
||||
|
const template = |
||||
|
`<script setup lang="ts">
|
||||
|
import HeaderXcx from '@/components/Header/HeaderXcx.vue' |
||||
|
</script> |
||||
|
<template> |
||||
|
<view class=""> |
||||
|
<HeaderXcx :leftTxt="'标题'" :textColor="'#fff'" :goBack="false"></HeaderXcx> |
||||
|
${title} |
||||
|
</view> |
||||
|
</template> |
||||
|
<style lang="scss" scoped></style>`;
|
||||
|
createStream.write(template); |
||||
|
createStream.end(); |
||||
|
console.log('\x1B[34m', `pages ${name} created successfully.`); |
||||
|
} |
||||
|
console.log('\x1B[32m%s\x1B[39m', '\n All files are created successfully.\n'); |
||||
|
} |
||||
|
|
||||
|
addPages(newPages); |
||||
@ -0,0 +1,4 @@ |
|||||
|
if (!/pnpm/.test(process.env.npm_execpath || '')) { |
||||
|
console.warn(`\u001b[33mThis repository must using pnpm as the package manager ` + ` for scripts to work properly.\u001b[39m\n`) |
||||
|
process.exit(1) |
||||
|
} |
||||
File diff suppressed because it is too large
File diff suppressed because it is too large
|
Before Width: | Height: | Size: 1.7 KiB |
@ -1,51 +0,0 @@ |
|||||
const fs = require('fs') |
|
||||
|
|
||||
const publish = () => { |
|
||||
const src = './dist/build/h5' |
|
||||
const dest = '../niucloud/public/wap' |
|
||||
|
|
||||
solve() |
|
||||
|
|
||||
// 目标目录不存在停止复制 |
|
||||
try { |
|
||||
const dir = fs.readdirSync(dest) |
|
||||
} catch (e) { |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
// 删除目标目录下文件 |
|
||||
fs.rm(dest, { recursive: true }, err => { |
|
||||
if(err) { |
|
||||
console.log(err) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
fs.cp(src, dest, { recursive: true }, (err) => { |
|
||||
if (err) { |
|
||||
console.error(err) |
|
||||
} |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const solve = () => { |
|
||||
const src = './dist/build/h5/assets' |
|
||||
const filemaps = fs.readdirSync(src) |
|
||||
|
|
||||
filemaps.forEach(file => { |
|
||||
if (/^(index-)(\w{8})(.js)$/.test(file)) { |
|
||||
const path = `${src}/${file}` |
|
||||
let content = fs.readFileSync(path, 'utf-8') |
|
||||
const first = 'const match = location.href.match(/\\/wap\\/(\\d*)\\//);' |
|
||||
|
|
||||
if (content.indexOf(first) == -1) { |
|
||||
content = first + content |
|
||||
const replace = 'router:{mode:"history",base: match ? `/wap/${match[1]}/` : "/wap/",assets:"assets",routerBase: match ? `/wap/${match[1]}/` : "/wap/"},darkmode' |
|
||||
content = content.replace(/router:{(.*?)},darkmode/s, replace) |
|
||||
fs.writeFileSync(path, content, 'utf8') |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
publish() |
|
||||
@ -1,111 +1,29 @@ |
|||||
|
<template> |
||||
|
<view id="app"> |
||||
|
<router-view></router-view> |
||||
|
</view> |
||||
|
</template> |
||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app' |
// import routingIntercept from '@/permission' |
||||
import { launchInterceptor } from '@/utils/interceptor' |
|
||||
import { getToken, isWeixinBrowser, getSiteId } from '@/utils/common' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import useConfigStore from '@/stores/config' |
|
||||
import useSystemStore from '@/stores/system' |
|
||||
import { useLogin } from '@/hooks/useLogin' |
|
||||
import { useShare } from '@/hooks/useShare' |
|
||||
|
|
||||
onLaunch(async(data) => { |
onLaunch(() => { |
||||
|
// routingIntercept() |
||||
// // 添加初始化拦截器 |
|
||||
// launchInterceptor() |
|
||||
|
|
||||
// // #ifdef H5 |
|
||||
// uni.getSystemInfoSync().platform == 'ios' && (uni.setStorageSync('initUrl', location.href)) |
|
||||
|
|
||||
// // 传输给后台数据 |
|
||||
// window.parent.postMessage(JSON.stringify({ |
|
||||
// type: 'appOnLaunch', |
|
||||
// message: '初始化加载完成' |
|
||||
// }), '*'); |
|
||||
|
|
||||
// // 监听父页面发来的消息 |
|
||||
// window.addEventListener('message', event => { |
|
||||
// try { |
|
||||
// let data = { |
|
||||
// type: '' |
|
||||
// }; |
|
||||
// if (typeof event.data == 'string') { |
|
||||
// data = JSON.parse(event.data) |
|
||||
// } else if (typeof event.data == 'object') { |
|
||||
// data = event.data |
|
||||
// } |
|
||||
// if (data.type && data.type == 'appOnReady') { |
|
||||
// window.parent.postMessage(JSON.stringify({ |
|
||||
// type: 'appOnReady', |
|
||||
// message: '加载完成' |
|
||||
// }), '*'); |
|
||||
// } |
|
||||
// } catch (e) { |
|
||||
// console.log('uni-app App.vue 接受数据错误', e) |
|
||||
// } |
|
||||
// }, false); |
|
||||
|
|
||||
// // 缺少站点id,拦截 |
|
||||
// if (process.env.NODE_ENV == 'development' && (getSiteId(uni.getStorageSync('wap_site_id') || import.meta.env.VITE_SITE_ID) === '')) return; |
|
||||
|
|
||||
// const { wechatInit } = useShare() |
|
||||
// wechatInit() |
|
||||
// // #endif |
|
||||
|
|
||||
// const configStore = useConfigStore() |
|
||||
// await configStore.getTabbarConfig() |
|
||||
// await configStore.getLoginConfig() |
|
||||
|
|
||||
// useSystemStore().getMapFn() |
|
||||
// useSystemStore().getSiteInfoFn() |
|
||||
|
|
||||
// // try { |
|
||||
// // // 隐藏tabbar |
|
||||
// // uni.hideTabBar() |
|
||||
// // } catch (e) { |
|
||||
|
|
||||
// // } |
|
||||
|
|
||||
// // 判断是否已登录 |
|
||||
// if (getToken()) { |
|
||||
// const memberStore = useMemberStore() |
|
||||
// await memberStore.setToken(getToken()) |
|
||||
|
|
||||
// setTimeout(() => { |
|
||||
// if (!uni.getStorageSync('openid')) { |
|
||||
// const memberInfo = useMemberStore().info |
|
||||
// // #ifdef MP-WEIXIN |
|
||||
// memberInfo && memberInfo.weapp_openid && uni.setStorageSync('openid', memberInfo.weapp_openid) |
|
||||
// // #endif |
|
||||
// // #ifdef H5 |
|
||||
// isWeixinBrowser() && memberInfo && memberInfo.wx_openid && uni.setStorageSync('openid', memberInfo.wx_openid) |
|
||||
// // #endif |
|
||||
// } |
|
||||
// }, 1000) |
|
||||
// } |
|
||||
|
|
||||
// if (!getToken()) { |
|
||||
// const login = useLogin() |
|
||||
// // 第三方平台自动登录 |
|
||||
// // #ifdef MP |
|
||||
// login.getAuthCode() |
|
||||
// // #endif |
|
||||
// // #ifdef H5 |
|
||||
// if (isWeixinBrowser()) { |
|
||||
// data.query.code ? login.authLogin(data.query.code) : login.getAuthCode('snsapi_userinfo') |
|
||||
// } |
|
||||
// // #endif |
|
||||
// } |
|
||||
}) |
}) |
||||
|
|
||||
onShow(() => { |
onShow(() => { |
||||
|
console.log('App Show') |
||||
}) |
}) |
||||
|
|
||||
onHide(() => { |
onHide(() => { |
||||
|
console.log('App Hide') |
||||
}) |
}) |
||||
|
// 全局变量 |
||||
|
// provide('globalObj', <globalObjInt>{ |
||||
|
// // 公用跳转方法 |
||||
|
// goToPage |
||||
|
// }); |
||||
|
// // 引入静态资源 |
||||
</script> |
</script> |
||||
|
|
||||
<style> |
<style lang="scss"> |
||||
uni-page-head { |
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */ |
||||
display: none !important; |
@import 'uview-plus/index.scss'; |
||||
} |
|
||||
</style> |
</style> |
||||
|
|||||
@ -0,0 +1,25 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export function getVoteList(data: pageType) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_list', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getVoteDetail(data: { id: number }) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_result_detail', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getVoteResult(data: pageType) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_result', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export function getOpenid(data: { code: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/openid', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getMobile(data: { code: string; openid: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/mobile', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function getAdminPhone() { |
||||
|
return request.http({ |
||||
|
url: '/api/admin_mobile', |
||||
|
method: 'GET' |
||||
|
}) |
||||
|
} |
||||
|
//用户签到
|
||||
|
export function getSign(data: { meetId: string; openid: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/sign', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//扫码时手机号获取用户信息
|
||||
|
export function getmemberMobileGet(data: { meetId: string; openid: string; mobile: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile_get', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,61 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
export interface listType { |
||||
|
name: string |
||||
|
age: number |
||||
|
sex: number |
||||
|
nation: string |
||||
|
mobile: string |
||||
|
position: string |
||||
|
work_unit: string |
||||
|
} |
||||
|
|
||||
|
export interface dateListtype extends listType { |
||||
|
id: number |
||||
|
} |
||||
|
|
||||
|
export function infoForOpenid(data: { openid: string; mobile: string ; meetId: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile_get', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 手机号获取用户信息
|
||||
|
export function getMember_mobile(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function list(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_name', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function update(data: { [n: string]: string }, openid: string) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_update', |
||||
|
data: Object.assign(data, { openid }) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function bind(data: { id: number; openid: string }) { |
||||
|
return request.http({ |
||||
|
url: '/api/name_sub', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export function add(data: listType) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_add', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
import { request } from '@/utils/http' |
||||
|
|
||||
|
// 获取投票选举(正在进行)
|
||||
|
export function getVoteprogress(id: string) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_progress?meetId='+ id, |
||||
|
method: 'GET' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
//用户投票
|
||||
|
export function voteMember(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/vote_member', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 获取我的选举
|
||||
|
export function getMyvote(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/my_vote', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 手机号获取用户信息
|
||||
|
export function getMember_mobile(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/member_mobile', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 判断用户是否签到
|
||||
|
export function getIs_sign(data: any) { |
||||
|
return request.http({ |
||||
|
url: '/api/is_sign', |
||||
|
method: 'GET', |
||||
|
data |
||||
|
}) |
||||
|
} |
||||
@ -1,97 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 用户名登录 |
|
||||
*/ |
|
||||
export function usernameLogin(data : AnyObject) { |
|
||||
return request.get('login', data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 手机验证码登录 |
|
||||
*/ |
|
||||
export function mobileLogin(data : AnyObject) { |
|
||||
return request.post('login/mobile', data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取登录配置 |
|
||||
*/ |
|
||||
export function getConfig() { |
|
||||
return request.get('login/config') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 退出登录 |
|
||||
*/ |
|
||||
export function logout() { |
|
||||
return request.put('auth/logout') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 用户名注册 |
|
||||
*/ |
|
||||
export function usernameRegister(data : AnyObject) { |
|
||||
let url = 'register' |
|
||||
if(uni.getStorageSync('pid')){ |
|
||||
data.pid = uni.getStorageSync('pid'); |
|
||||
} |
|
||||
return request.post(url, data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 手机号注册 |
|
||||
*/ |
|
||||
export function mobileRegister(data : AnyObject) { |
|
||||
let url = 'register/mobile' |
|
||||
if(uni.getStorageSync('pid')){ |
|
||||
data.pid = uni.getStorageSync('pid'); |
|
||||
} |
|
||||
return request.post(url, data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 微信公众号授权信息 |
|
||||
*/ |
|
||||
export function wechatUser(data : AnyObject) { |
|
||||
return request.get('wechat/user', data, { showErrorMessage: false }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 微信公众号授权信息登录(openid) |
|
||||
*/ |
|
||||
export function wechatUserLogin(data : AnyObject) { |
|
||||
return request.post('wechat/userlogin', data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 微信公众号授权登录 |
|
||||
*/ |
|
||||
export function wechatLogin(data : AnyObject) { |
|
||||
return request.post('wechat/login', data, { showErrorMessage: false }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 微信小程序授权登录 |
|
||||
*/ |
|
||||
export function weappLogin(data : AnyObject) { |
|
||||
return request.post('weapp/login', data, { showErrorMessage: false }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 绑定手机号 |
|
||||
*/ |
|
||||
export function bind(data : AnyObject) { |
|
||||
let url = 'bind' |
|
||||
if(uni.getStorageSync('pid')){ |
|
||||
data.pid = uni.getStorageSync('pid'); |
|
||||
} |
|
||||
return request.post(url, data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 记录会员访问日志 |
|
||||
*/ |
|
||||
export function memberLog(data : AnyObject) { |
|
||||
return request.post('member/log', data, { showErrorMessage: false }) |
|
||||
} |
|
||||
@ -1,39 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 绑定设备 |
|
||||
*/ |
|
||||
export function set_equipment(params: AnyObject) { |
|
||||
return request.get(`member/set_equipment`, params) |
|
||||
} |
|
||||
/** |
|
||||
* 档案列表 |
|
||||
*/ |
|
||||
export function list_archives() { |
|
||||
return request.get(`member/list_archives`) |
|
||||
} |
|
||||
/** |
|
||||
* 操作档案 |
|
||||
*/ |
|
||||
export function edit_archives(data : any) { |
|
||||
return request.post(`member/edit_archives`, data) |
|
||||
} |
|
||||
/** |
|
||||
* 删除档案 |
|
||||
*/ |
|
||||
export function del_archives(id : number) { |
|
||||
return request.get(`member/del_archives?id=`+ id) |
|
||||
} |
|
||||
/** |
|
||||
* 设备列表 |
|
||||
*/ |
|
||||
export function list_equipment() { |
|
||||
return request.get(`member/list_equipment`) |
|
||||
} |
|
||||
/** |
|
||||
* 解绑设备 |
|
||||
*/ |
|
||||
export function del_equipment(id : number) { |
|
||||
return request.get(`member/del_equipment?id=`+ id) |
|
||||
} |
|
||||
@ -1,29 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 获取自定义页面信息 |
|
||||
*/ |
|
||||
export function getDiyInfo(params: Record<string, any>) { |
|
||||
return request.get('diy/diy', params) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取底部导航信息 |
|
||||
*/ |
|
||||
export function getTabbarInfo(params: Record<string, any>) { |
|
||||
return request.get('diy/tabbar', params) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取底部导航列表 |
|
||||
*/ |
|
||||
export function getTabbarList(params: Record<string, any>) { |
|
||||
return request.get('diy/tabbar/list', params) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取页面分享信息 |
|
||||
*/ |
|
||||
export function getShareInfo(params: Record<string, any>) { |
|
||||
return request.get('diy/share', params) |
|
||||
} |
|
||||
@ -1,101 +0,0 @@ |
|||||
import request from "@/utils/request"; |
|
||||
|
|
||||
// 获取轮播图
|
|
||||
export function getCarousel() { |
|
||||
return request.get('/shop/slideshow/list') |
|
||||
} |
|
||||
|
|
||||
// 获取分类
|
|
||||
export function getClassification() { |
|
||||
return request.get('/shop/homeCategory/list') |
|
||||
} |
|
||||
|
|
||||
// 获取文章分类
|
|
||||
export function getArticle(data) { |
|
||||
return request.get('/cms/category',data) |
|
||||
} |
|
||||
|
|
||||
// 获取医生
|
|
||||
export function getDoctor(data) { |
|
||||
return request.get('/shop/doctor/list',data) |
|
||||
} |
|
||||
// 获取驿站
|
|
||||
export function getDak(data) { |
|
||||
return request.get('/shop/communityStation/list',data) |
|
||||
} |
|
||||
|
|
||||
// 获取科室分类
|
|
||||
export function getDepartmentClassification(data) { |
|
||||
return request.get('/shop/doctorsDepartment/list',data) |
|
||||
} |
|
||||
|
|
||||
// 获取驿站详情
|
|
||||
export function getRelayDetails(data) { |
|
||||
return request.get('/shop/communityStation/info',data) |
|
||||
} |
|
||||
|
|
||||
// 获取行政区划
|
|
||||
export function getAdministrativeDivision() { |
|
||||
return request.get('/accompany/getAreaTree') |
|
||||
} |
|
||||
|
|
||||
// 获取专题列表
|
|
||||
export function getTopicsList(data) { |
|
||||
return request.get('/cms/article',data) |
|
||||
} |
|
||||
|
|
||||
// 获取专题详情
|
|
||||
export function getTopicsDetails(id) { |
|
||||
return request.get(`/cms/article/${id}`) |
|
||||
} |
|
||||
|
|
||||
// 获取医院分类
|
|
||||
export function getHospitalClassification() { |
|
||||
return request.get(`/shop/doctor/getHospitalsAll`) |
|
||||
} |
|
||||
|
|
||||
// 获取医生详情
|
|
||||
export function getDoctorDetails(data) { |
|
||||
return request.get(`/shop/goods/detail`,data) |
|
||||
} |
|
||||
|
|
||||
// 商品详情
|
|
||||
export function getProductDetails(data) { |
|
||||
return request.get(`/shop/goods/detail`,data) |
|
||||
} |
|
||||
|
|
||||
// 订单计算
|
|
||||
export function orderCalculation(data) { |
|
||||
return request.get(`/shop/order_create/calculate`,data) |
|
||||
} |
|
||||
|
|
||||
// 订单创建
|
|
||||
export function orderCreation(data) { |
|
||||
return request.post(`/shop/order_create/create`,data) |
|
||||
} |
|
||||
|
|
||||
// 获取通知
|
|
||||
export function getNotifications(data) { |
|
||||
return request.get(`/shop/memberNotifications/lists`,data ) |
|
||||
} |
|
||||
|
|
||||
// 获取用户信息
|
|
||||
export function getUserInfo() { |
|
||||
return request.get(`/member/member`) |
|
||||
} |
|
||||
|
|
||||
// 获取客服
|
|
||||
export function customerService() { |
|
||||
return request.get(`/shop/shopConfig/info`) |
|
||||
} |
|
||||
|
|
||||
|
|
||||
// 获取支付信息
|
|
||||
export function getPaymentInfo(trade_type,trade_id) { |
|
||||
return request.get(`/pay/info/${trade_type}/${trade_id}`) |
|
||||
} |
|
||||
|
|
||||
// 去支付
|
|
||||
export function toPay(data) { |
|
||||
return request.post(`/pay`,data) |
|
||||
} |
|
||||
@ -1,244 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
export function getMemberInfo() { |
|
||||
return request.get('member/member') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取积分流水 |
|
||||
*/ |
|
||||
export function getPointList(data : AnyObject) { |
|
||||
return request.get('member/account/point', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取不可提现余额流水 |
|
||||
*/ |
|
||||
export function getBalanceList(data : AnyObject) { |
|
||||
return request.get('member/account/balance', data) |
|
||||
} |
|
||||
/** |
|
||||
* 获取余额流水,条件获取 |
|
||||
*/ |
|
||||
export function getBalanceListAll(data : AnyObject) { |
|
||||
return request.get('member/account/balance_list', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取可提现余额流水 |
|
||||
*/ |
|
||||
export function getMoneyList(data : AnyObject) { |
|
||||
return request.get('member/account/money', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 会员信息修改 |
|
||||
*/ |
|
||||
export function modifyMember(data : AnyObject) { |
|
||||
return request.put(`member/modify/${data.field}`, data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 登录会员绑定手机号 |
|
||||
*/ |
|
||||
export function bindMobile(data : AnyObject) { |
|
||||
return request.put('member/mobile', data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 提现转账方式 |
|
||||
*/ |
|
||||
export function cashOutTransferType() { |
|
||||
return request.get('member/cash_out/transfertype') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 提现配置 |
|
||||
*/ |
|
||||
export function cashOutConfig() { |
|
||||
return request.get('member/cash_out/config') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 申请余额提现 |
|
||||
*/ |
|
||||
export function cashOutApply(data : AnyObject) { |
|
||||
return request.post('member/cash_out/apply', data, { showSuccessMessage: true, showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取提现账户信息 |
|
||||
*/ |
|
||||
export function getCashoutAccountInfo(data : AnyObject) { |
|
||||
return request.get(`member/cashout_account/${data.account_id}`, {}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取首条提现账户信息 |
|
||||
*/ |
|
||||
export function getFirstCashoutAccountInfo(data : AnyObject) { |
|
||||
return request.get('member/cashout_account/firstinfo', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取提现账户列表 |
|
||||
*/ |
|
||||
export function getCashoutAccountList(data : AnyObject) { |
|
||||
return request.get(`member/cashout_account`, data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取提现记录列表 |
|
||||
*/ |
|
||||
export function getCashOutList(data : AnyObject) { |
|
||||
return request.get(`member/cash_out`, data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取提现记录详情 |
|
||||
*/ |
|
||||
export function getCashOutDetail(id : number) { |
|
||||
return request.get(`member/cash_out/${id}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 添加提现账户 |
|
||||
*/ |
|
||||
export function addCashoutAccount(data : AnyObject) { |
|
||||
return request.post('member/cashout_account', data, { showSuccessMessage: true, showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 添加提现账户 |
|
||||
*/ |
|
||||
export function editCashoutAccount(data : AnyObject) { |
|
||||
return request.put(`member/cashout_account/${data.account_id}`, data, { showSuccessMessage: true, showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 删除提现账户 |
|
||||
*/ |
|
||||
export function deleteCashoutAccount(accountId: number) { |
|
||||
return request.delete(`member/cashout_account/${accountId}`, { showSuccessMessage: true, showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 佣金账户流水 |
|
||||
*/ |
|
||||
export function getMemberCommission(data : AnyObject) { |
|
||||
return request.get(`member/account/commission`,data) |
|
||||
} |
|
||||
/** |
|
||||
* 佣金列表 |
|
||||
*/ |
|
||||
export function getCommissionList(data : AnyObject) { |
|
||||
return request.get(`member/account/commission`, data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取账号变动类型 |
|
||||
*/ |
|
||||
export function getAccountType(params: Record<string, any>) { |
|
||||
return request.get(`member/account/fromtype/${params.account_type}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取会员收货地址列表 |
|
||||
* @param params |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function getAddressList(params: Record<string, any>) { |
|
||||
return request.get(`member/address`, params) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取会员收货地址详情 |
|
||||
* @param id 会员收货地址id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function getAddressInfo(id: number) { |
|
||||
return request.get(`member/address/${id}`); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 添加会员收货地址 |
|
||||
* @param params |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function addAddress(params: Record<string, any>) { |
|
||||
return request.post('member/address', params, { showErrorMessage: true, showSuccessMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 编辑会员收货地址 |
|
||||
* @param params |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function editAddress(params: Record<string, any>) { |
|
||||
return request.put(`member/address/${params.id}`, params, { showErrorMessage: true, showSuccessMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 删除会员收货地址 |
|
||||
* @param id |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function deleteAddress(id: number) { |
|
||||
return request.delete(`member/address/${id}`, { showErrorMessage: true, showSuccessMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取会员等级 |
|
||||
*/ |
|
||||
export function getMemberLevel() { |
|
||||
return request.get(`member/level`); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取成长值任务 |
|
||||
*/ |
|
||||
export function getTaskGrowth() { |
|
||||
return request.get(`task/growth`); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取签到日期 |
|
||||
*/ |
|
||||
export function getSignInfo(data : AnyObject) { |
|
||||
return request.get(`member/sign/info/${data.year}/${data.month}`, {}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取日签到奖励 |
|
||||
*/ |
|
||||
export function getDayPack(data : AnyObject) { |
|
||||
return request.get(`member/sign/award/${data.year}/${data.month}/${data.day}`) |
|
||||
} |
|
||||
/** |
|
||||
* 获取签到设置 |
|
||||
*/ |
|
||||
export function getSignConfig() { |
|
||||
return request.get(`member/sign/config`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 点击签到 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function setSign() { |
|
||||
return request.post('member/sign') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取个人积分 |
|
||||
*/ |
|
||||
export function getMemberAccountPointcount() { |
|
||||
return request.get(`member/account/pointcount`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取积分任务 |
|
||||
*/ |
|
||||
export function getTaskPoint() { |
|
||||
return request.get(`task/point`) |
|
||||
} |
|
||||
@ -1,8 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 个人中心 |
|
||||
*/ |
|
||||
export function getUserDet() { |
|
||||
return request.get('member/member') |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 支付 |
|
||||
*/ |
|
||||
export function pay(data : AnyObject) { |
|
||||
return request.post(`pay`, data, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取支付信息 |
|
||||
*/ |
|
||||
export function getPayInfo(tradeType : string, tradeId : number) { |
|
||||
return request.get(`pay/info/${tradeType}/${tradeId}`, {}, { showErrorMessage: true }) |
|
||||
} |
|
||||
@ -1,76 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 商品分类树状结构 |
|
||||
*/ |
|
||||
export function goodsTree() { |
|
||||
return request.get(`shop/goods/category/tree`) |
|
||||
} |
|
||||
/** |
|
||||
* 商品列表 |
|
||||
*/ |
|
||||
export function goodsList(params : Record<string, any>) { |
|
||||
return request.get(`shop/goods/pages`, params) |
|
||||
} |
|
||||
/** |
|
||||
* 获取商品详情 |
|
||||
*/ |
|
||||
export function goodsDetail(params : Record<string, any>) { |
|
||||
return request.get(`shop/goods/detail`, params) |
|
||||
} |
|
||||
/** |
|
||||
* 商品收藏-添加 |
|
||||
*/ |
|
||||
export function goodsCollect(id : number) { |
|
||||
return request.post(`shop/goods/collect/`+id) |
|
||||
} |
|
||||
/** |
|
||||
* 购物车-添加 |
|
||||
*/ |
|
||||
export function shopCart(data : any) { |
|
||||
return request.post(`shop/cart`, data) |
|
||||
} |
|
||||
/** |
|
||||
* 购物车-列表 |
|
||||
*/ |
|
||||
export function shopcartList() { |
|
||||
return request.get(`shop/cart`) |
|
||||
} |
|
||||
/** |
|
||||
* 购物车-删除 |
|
||||
*/ |
|
||||
export function deleteCart(data : any) { |
|
||||
return request.put(`shop/cart/delete`, data) |
|
||||
} |
|
||||
/** |
|
||||
* 获取商品分类列表 |
|
||||
*/ |
|
||||
export function categoryList(params : Record<string, any>) { |
|
||||
return request.get(`shop/goods/category/list`, params) |
|
||||
} |
|
||||
/** |
|
||||
* 订单-计算(创建订单第1步) |
|
||||
*/ |
|
||||
export function calculateCreate(params : Record<string, any>) { |
|
||||
return request.get(`shop/order_create/calculate`, params) |
|
||||
} |
|
||||
/** |
|
||||
* 订单-创建(创建订单第2步-完成订单的创建) |
|
||||
*/ |
|
||||
export function orderCreate(data : Record<string, any>) { |
|
||||
return request.post(`shop/order_create/create`, data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取支付信息 |
|
||||
*/ |
|
||||
export function getPayInfo(tradeType : string, tradeId : number) { |
|
||||
return request.get(`pay/info/${tradeType}/${tradeId}`, {}, { showErrorMessage: true }) |
|
||||
} |
|
||||
/** |
|
||||
* 去支付(第2步) |
|
||||
|
|
||||
*/ |
|
||||
export function goPayy(data : Record<string, any>) { |
|
||||
return request.post(`pay`,data) |
|
||||
} |
|
||||
@ -1,147 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 获取验证码 |
|
||||
*/ |
|
||||
export function getCaptcha() { |
|
||||
return request.get('captcha', {}, {showErrorMessage: true}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取微信公众号授权码 |
|
||||
*/ |
|
||||
export function getWechatAuthCode(data: AnyObject) { |
|
||||
return request.get('wechat/codeurl', data, {showErrorMessage: false}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 同步微信信息 |
|
||||
*/ |
|
||||
export function wechatSync(data: AnyObject) { |
|
||||
return request.post('wechat/sync', data, {showErrorMessage: false}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取协议信息 |
|
||||
*/ |
|
||||
export function getAgreementInfo(key: string) { |
|
||||
return request.get(`agreement/${key}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 重置密码 |
|
||||
*/ |
|
||||
export function resetPassword(data: AnyObject) { |
|
||||
return request.post(`password/reset`, data, {showErrorMessage: true}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 发送短信验证码 |
|
||||
*/ |
|
||||
export function sendSms(data: AnyObject) { |
|
||||
return request.post(`send/mobile/${data.type}`, data, {showErrorMessage: true}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取微信jssdk config |
|
||||
*/ |
|
||||
export function getWechatSkdConfig(data: AnyObject) { |
|
||||
return request.get('wechat/jssdkconfig', data, {showErrorMessage: false}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 上传图片 |
|
||||
*/ |
|
||||
export function uploadImage(data: AnyObject) { |
|
||||
return request.upload('file/image', data, {showErrorMessage: true}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 拉取图片 |
|
||||
*/ |
|
||||
export function fetchImage(data: AnyObject) { |
|
||||
return request.post('file/image/fetch', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 拉取base64图片 |
|
||||
*/ |
|
||||
export function fetchBase64Image(data: AnyObject) { |
|
||||
return request.post('file/image/base64', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取站点信息 |
|
||||
*/ |
|
||||
export function getSiteInfo() { |
|
||||
return request.get('site') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取微信小程序订阅消息模板id |
|
||||
*/ |
|
||||
export function getWeappTemplateId(keys: string) { |
|
||||
return request.get('weapp/subscribemsg', {keys}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取下级地址列表 |
|
||||
* @param pid |
|
||||
*/ |
|
||||
export function getAreaListByPid(pid: number = 0) { |
|
||||
return request.get(`area/list_by_pid/${pid}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取地址树列表 |
|
||||
* @param level |
|
||||
*/ |
|
||||
export function getAreatree(level: number = 1) { |
|
||||
return request.get(`area/tree/${level}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取地址 |
|
||||
* @param code |
|
||||
*/ |
|
||||
export function getAreaByCode(code: number | string) { |
|
||||
return request.get(`area/code/${code}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 通过经纬度查询地址 |
|
||||
* @param params |
|
||||
*/ |
|
||||
export function getAddressByLatlng(params: Record<string, any>) { |
|
||||
return request.get(`area/address_by_latlng`, params, {showErrorMessage: true}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取手机端首页列表 |
|
||||
*/ |
|
||||
export function getWapIndexList(data: AnyObject) { |
|
||||
return request.get('wap_index', data) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取海报 |
|
||||
* @returns |
|
||||
*/ |
|
||||
export function getPoster(params: Record<string, any>) { |
|
||||
return request.get("poster", params) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取地图设置 |
|
||||
*/ |
|
||||
export function getMap() { |
|
||||
return request.get('map') |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 通过外部交易号获取消息跳转路径 |
|
||||
* @param params |
|
||||
*/ |
|
||||
export function getMsgJumpPath(params: Record<string, any>) { |
|
||||
return request.get('weapp/getMsgJumpPath', params) |
|
||||
} |
|
||||
@ -1,47 +0,0 @@ |
|||||
import request from '@/utils/request' |
|
||||
|
|
||||
/** |
|
||||
* 获取核销信息 |
|
||||
*/ |
|
||||
export function getVerifyCode(type: string ,params: AnyObject) { |
|
||||
return request.get('verify', {type, data: params}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取核销记录 |
|
||||
*/ |
|
||||
export function getVerifyRecords(params: Record<string, any>) { |
|
||||
return request.get('verify_records', params) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 判断是否是核销员 |
|
||||
*/ |
|
||||
export function getCheckVerifier() { |
|
||||
return request.get('check_verifier') |
|
||||
} |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* 获取核销信息 |
|
||||
*/ |
|
||||
export function getVerifierInfo(code: string) { |
|
||||
return request.get(`get_verify_by_code/${code}`) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 核销 |
|
||||
*/ |
|
||||
export function verify(code: string) { |
|
||||
return request.post(`verify/${code}`,{}, { showSuccessMessage: true, showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 获取核销详情 |
|
||||
*/ |
|
||||
export function getVerifyDetail(code: string) { |
|
||||
return request.get(`verify_detail/${code}`,{}, { showErrorMessage: true }) |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
@ -1,219 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view class="diy-active-cube relative"> |
|
||||
<view class="active-cube-wrap p-[20rpx]"> |
|
||||
<view class="flex items-center" v-if="diyComponent.titleStyle.value == 'style-1'"> |
|
||||
<view class="mr-[20rpx] font-bold text-[32rpx]" :style="{color: diyComponent.titleColor }" @click="diyStore.toRedirect(diyComponent.textLink)">{{ diyComponent.text }}</view> |
|
||||
<view v-if="diyComponent.subTitle.text" @click="diyStore.toRedirect(diyComponent.subTitle.link)" class="text-center text-[24rpx] rounded-[40rpx] rounded-tl-none py-[10rpx] px-[20rpx]" :style="{'color': diyComponent.subTitle.textColor, background: 'linear-gradient(90deg, '+ diyComponent.subTitle.startColor + ', '+ diyComponent.subTitle.endColor + ')'}">{{ diyComponent.subTitle.text }}</view> |
|
||||
</view> |
|
||||
<view class="flex items-center" v-if="diyComponent.titleStyle.value == 'style-2'"> |
|
||||
<view class="mr-[20rpx] font-bold text-[32rpx]" :style="{color: diyComponent.titleColor }" @click="diyStore.toRedirect(diyComponent.textLink)">{{ diyComponent.text }}</view> |
|
||||
<view v-if="diyComponent.subTitle.text" @click="diyStore.toRedirect(diyComponent.subTitle.link)" class="text-center text-[24rpx] rounded-[10rpx] py-[10rpx] px-[20rpx]" :style="{'color': diyComponent.subTitle.textColor, background: 'linear-gradient(90deg, '+ diyComponent.subTitle.startColor + ', '+ diyComponent.subTitle.endColor + ')'}">{{ diyComponent.subTitle.text }}</view> |
|
||||
</view> |
|
||||
<view class="flex items-center" v-if="diyComponent.titleStyle.value == 'style-3'"> |
|
||||
<view class="mr-[20rpx] font-bold text-[32rpx]" @click="diyStore.toRedirect(diyComponent.textLink)" :style="{color: diyComponent.titleColor }">{{ diyComponent.text }}</view> |
|
||||
<view class="relative h-[44rpx]" @click="diyStore.toRedirect(diyComponent.subTitle.link)"> |
|
||||
<view v-if="diyComponent.subTitle.text" class="text-center text-[24rpx] py-[10rpx] pl-[16rpx] pr-[36rpx]" :style="{'color': diyComponent.subTitle.textColor, background: 'linear-gradient(90deg, '+ diyComponent.subTitle.startColor + ', '+ diyComponent.subTitle.endColor + ')'}">{{ diyComponent.subTitle.text }}</view> |
|
||||
<image class="absolute left-0 top-0 bottom-0 !w-[16rpx] !h-[44rpx]" :src="img('static/resource/images/diy/active_cube/block_style2_1.png')" mode="scaleToFill"/> |
|
||||
<image class="absolute right-0 top-0 bottom-0 !w-[28rpx] !h-[44rpx]" :src="img('static/resource/images/diy/active_cube/block_style2_2.png')" mode="scaleToFill"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="flex items-center justify-between" v-if="diyComponent.titleStyle.value == 'style-4'"> |
|
||||
<view class="font-bold text-[32rpx]" @click="diyStore.toRedirect(diyComponent.textLink)" :style="{color: diyComponent.titleColor }">{{ diyComponent.text }}</view> |
|
||||
<view v-if="diyComponent.subTitle.text" @click="diyStore.toRedirect(diyComponent.subTitle.link)" class="text-[24rpx] rounded-[40rpx] py-[10rpx] pl-[16rpx] pr-[12rpx] flex items-center" :style="{'color': diyComponent.subTitle.textColor, background: 'linear-gradient(90deg, '+ diyComponent.subTitle.startColor + ', '+ diyComponent.subTitle.endColor + ')'}"> |
|
||||
<text>{{ diyComponent.subTitle.text }}</text> |
|
||||
<text class="nc-iconfont nc-icon-youV6xx !text-[26rpx]"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<view class="bd flex flex-wrap justify-between"> |
|
||||
<template v-for="item in diyComponent.list" :key="item.id"> |
|
||||
<view v-if="diyComponent.blockStyle.value == 'style-1'" @click="diyStore.toRedirect(item.link)" class="item flex justify-between p-[20rpx] bg-white mt-[20rpx] rounded-[16rpx]" :style="{ backgroundColor : diyComponent.elementBgColor }"> |
|
||||
<view class="flex-1 flex items-baseline flex-col"> |
|
||||
<view class="text--[28rpx] pb-[20rpx]" :style="{ fontWeight : diyComponent.blockStyle.fontWeight }">{{ item.title.text }}</view> |
|
||||
<view class="text--[24rpx] text-gray-500 pb-[20rpx]">{{ item.subTitle.text }}</view> |
|
||||
<view class="link relative text-[24rpx] leading-[40rpx] flex items-center text-white rounded-r-[20rpx] h-[40rpx] pl-[26rpx] pr-[10rpx]" :style="btnCss(item.moreTitle)" v-if="item.moreTitle.text"> |
|
||||
<text class="mr-[8rpx]">{{ item.moreTitle.text }}</text> |
|
||||
<text class="iconfont iconjiantou-you-cuxiantiao-fill !text-[20rpx] text-[#fff]"></text> |
|
||||
<image class="absolute left-0 top-0 bottom-0 !w-[28rpx]" :src="img('static/resource/images/diy/active_cube/block_style1_1.png')" mode="scaleToFill"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="img-box ml-[10rpx] w-[130rpx]" v-if="item.imageUrl"> |
|
||||
<image :src="img(item.imageUrl)" mode="aspectFit" /> |
|
||||
</view> |
|
||||
<view class="img-box ml-[10rpx] flex items-center justify-center w-[130rpx] bg-[#f3f4f6]" v-else> |
|
||||
<u-icon name="photo" color="#999" size="50"></u-icon> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-if="diyComponent.blockStyle.value == 'style-2'" @click="diyStore.toRedirect(item.link)" class="item flex justify-between p-[20rpx] bg-white mt-[20rpx] rounded-[16rpx]" :style="{ backgroundColor : diyComponent.elementBgColor }"> |
|
||||
<view class="flex-1 flex items-baseline flex-col"> |
|
||||
<view class="text--[28rpx] pb-[20rpx]" :style="{ fontWeight : diyComponent.blockStyle.fontWeight }">{{ item.title.text }}</view> |
|
||||
<view class="text--[24rpx] text-gray-500 pb-[20rpx]">{{ item.subTitle.text }}</view> |
|
||||
<view class="link relative text-[24rpx] leading-[40rpx] flex items-center text-white rounded-[20rpx] h-[40rpx] pl-[20rpx] pr-[10rpx]" :style="btnCss(item.moreTitle)" v-if="item.moreTitle.text"> |
|
||||
<text class="mr-[8rpx]">{{ item.moreTitle.text }}</text> |
|
||||
<text class="iconfont iconjiantou-you-cuxiantiao-fill !text-[20rpx] text-[#fff]"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="img-box ml-[10rpx] w-[130rpx]" v-if="item.imageUrl"> |
|
||||
<image :src="img(item.imageUrl)" mode="aspectFit" /> |
|
||||
</view> |
|
||||
<view class="img-box ml-[10rpx] flex items-center justify-center w-[130rpx] bg-[#f3f4f6]" v-else> |
|
||||
<u-icon name="photo" color="#999" size="50"></u-icon> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
</view> |
|
||||
|
|
||||
<scroll-view scroll-x="true" class="whitespace-nowrap" v-if="diyComponent.blockStyle.value == 'style-3'"> |
|
||||
<view v-for="(item,index) in diyComponent.list" :key="item.id" class="inline-flex"> |
|
||||
<view @click="diyStore.toRedirect(item.link)" class="flex flex-col items-center justify-between p-[10rpx] bg-white mt-[20rpx] w-[157rpx] h-[200rpx] rounded-[10rpx] box-border" :class="{'mr-[14rpx]': (index+1 != diyComponent.list.length)}"> |
|
||||
<view class="w-[141rpx] h-[141rpx]" v-if="item.imageUrl"> |
|
||||
<image class="w-[141rpx] h-[141rpx]" :src="img(item.imageUrl)" mode="aspectFit" /> |
|
||||
</view> |
|
||||
<view class="w-[141rpx] h-[141rpx] relative flex-shrink-0" v-else> |
|
||||
<view class="absolute left-0 top-0 flex items-center justify-center w-[141rpx] h-[141rpx] bg-[#f3f4f6]"> |
|
||||
<u-icon name="photo" color="#999" size="50"></u-icon> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="my-[10rpx] text-[26rpx]" :style="{ color : item.title.textColor,fontWeight : diyComponent.blockStyle.fontWeight }">{{ item.title.text }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</scroll-view> |
|
||||
|
|
||||
<scroll-view scroll-x="true" class="whitespace-nowrap" v-if="diyComponent.blockStyle.value == 'style-4'"> |
|
||||
<view v-for="(item,index) in diyComponent.list" :key="item.id" class="inline-flex"> |
|
||||
<view @click="diyStore.toRedirect(item.link)" class="flex flex-col items-center justify-between p-[4rpx] bg-[#F93D02] mt-[20rpx] rounded-[20rpx] box-border" :class="{'mr-[14rpx]': index+1 != diyComponent.list.length}" :style="{ background : 'linear-gradient('+ item.listFrame.startColor +','+ item.listFrame.endColor + ')' }"> |
|
||||
<view class="w-[149rpx] h-[149rpx] box-border px-[18rpx] pt-[16rpx] pb-[6rpx] bg-[#fff] flex flex-col items-center rounded-[16rpx]"> |
|
||||
<view class="w-[112rpx] h-[102rpx]" v-if="item.imageUrl"> |
|
||||
<image class="w-[112rpx] h-[102rpx]" :src="img(item.imageUrl)" mode="aspectFit" /> |
|
||||
</view> |
|
||||
<view class="w-[112rpx] h-[102rpx] relative flex-shrink-0" v-else> |
|
||||
<view class="absolute left-0 top-0 flex items-center justify-center w-[112rpx] h-[102rpx] bg-[#f3f4f6]"> |
|
||||
<u-icon name="photo" color="#999" size="50"></u-icon> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="relative -mt-[10rpx] text-[22rpx] bg-[#F3DAC5] text-[#ED6E00] rounded-[16rpx] px-[12rpx] leading-[36rpx]" :style="{ color : item.subTitle.textColor, background : 'linear-gradient(to right,'+ item.subTitle.startColor +','+ item.subTitle.endColor + ')' }">{{ item.subTitle.text }}</view> |
|
||||
</view> |
|
||||
<view class="mt-[10rpx] mb-[6rpx] text-[28rpx] text-[#fff]" :style="{ fontWeight : diyComponent.blockStyle.fontWeight }">{{ item.title.text }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</scroll-view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 活动魔方组件 |
|
||||
import { ref,computed, watch, onMounted, nextTick,getCurrentInstance } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
|
|
||||
return style; |
|
||||
|
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
const btnCss = (item:any) => { |
|
||||
var style = ''; |
|
||||
style += `background:linear-gradient(90deg,${item.startColor},${item.endColor});`; |
|
||||
return style; |
|
||||
}; |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'ActiveCube') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = ()=> { |
|
||||
nextTick(() => { |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.diy-active-cube').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.active-cube-wrap { |
|
||||
.bd { |
|
||||
.item { |
|
||||
width: calc(46% - 20rpx); |
|
||||
|
|
||||
image { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,634 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss" class="goods-carousel-search-wrap"> |
|
||||
<view class="relative pb-[20rpx]"> |
|
||||
<view class="bg-img" :class="{'!-bottom-[200rpx]': diyComponent.bgGradient == true}"> |
|
||||
<image v-if="diyComponent.swiper.list && diyComponent.swiper.list[swiperIndex].imageUrl" :src="img(diyComponent.swiper.list[swiperIndex].imageUrl)" mode="scaleToFill" class="w-full h-full" :show-menu-by-longpress="true"/> |
|
||||
<view v-else class="w-full h-full bg-[#ccc]"></view> |
|
||||
<view class="bg-img-box" :style="bgImgBoxStyle"></view> |
|
||||
</view> |
|
||||
|
|
||||
<view class="fixed-wrap" :class="[ diyStore.mode != 'decorate' ? diyComponent.positionWay : '' ]" :style="fixedStyle"> |
|
||||
<view class="diy-search-wrap relative z-10" @click="diyStore.toRedirect(diyComponent.search.link)" :style="navbarInnerStyle"> |
|
||||
<view class="img-wrap" v-if="diyComponent.search.logo"> |
|
||||
<image :src="img(diyComponent.search.logo)" mode="aspectFit"/> |
|
||||
</view> |
|
||||
<view class="search-content"> |
|
||||
<input type="text" class="uni-input" placeholder-style="color:#fff" placeholder-class="!text-[#fff] text-[24rpx] leading-[68rpx]" :placeholder="isShowSearchPlaceholder ? diyComponent.search.text : ''" disabled="true"/> |
|
||||
<text class="nc-iconfont nc-icon-sousuo-duanV6xx1"></text> |
|
||||
|
|
||||
<swiper class="swiper-wrap" :interval="diyComponent.search.hotWord.interval * 1000" autoplay="true" vertical="true" circular="true" v-if="!isShowSearchPlaceholder"> |
|
||||
<swiper-item class="swiper-item" v-for="(item) in diyComponent.search.hotWord.list" :key="item.id"> |
|
||||
<view class=" leading-[64rpx] text-[24rpx]">{{ item.text }}</view> |
|
||||
</swiper-item> |
|
||||
</swiper> |
|
||||
</view> |
|
||||
|
|
||||
</view> |
|
||||
|
|
||||
<view class="tab-list-wrap relative z-10" v-if="diyComponent.tab.control"> |
|
||||
<scroll-view scroll-x="true" class="scroll-wrap" :scroll-into-view="'a' + currTabIndex"> |
|
||||
<view @click="changeData({ source : 'home' },-1)" class="scroll-item" :class="[{ active: currTabIndex == -1 }]"> |
|
||||
<view class="name" :style="{'color': getTabColor(currTabIndex == -1)}">首页</view> |
|
||||
<view class="line" :style="{'background-color': getTabColor(currTabIndex == -1)}" v-if="currTabIndex == -1"></view> |
|
||||
</view> |
|
||||
<view v-for="(item, index) in diyComponent.tab.list" class="scroll-item" :class="[{ active: index == currTabIndex }]" @click="changeData(item,index)" :id="'a' + index" :key="index"> |
|
||||
<view class="name" :style="{'color': getTabColor(index == currTabIndex)}">{{ item.text }}</view> |
|
||||
<view class="line" :style="{'background-color': getTabColor(index == currTabIndex)}" v-if="index == currTabIndex"></view> |
|
||||
</view> |
|
||||
</scroll-view> |
|
||||
<view v-if="diyComponent.tab.list.length" class="absolute tab-btn nc-iconfont nc-icon-yingyongliebiaoV6xx" @click="tabAllPopup = true"></view> |
|
||||
</view> |
|
||||
|
|
||||
<view class="bg-img" v-if="fixedStyleBg"> |
|
||||
<image v-if="diyComponent.swiper.list && diyComponent.swiper.list[swiperIndex].imageUrl" :src="img(diyComponent.swiper.list[swiperIndex].imageUrl)" mode="scaleToFill" class="w-full h-full" :show-menu-by-longpress="true"/> |
|
||||
<view v-else class="w-full h-full bg-[#ccc]"></view> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<!-- 解决fixed定位后导航栏塌陷的问题 --> |
|
||||
<template v-if="diyStore.mode != 'decorate'"> |
|
||||
<view v-if="diyComponent.positionWay == 'fixed'" class="u-navbar-placeholder" :style="{ width: '100%', paddingTop: moduleHeight }"></view> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 轮播图 --> |
|
||||
<view class="relative" :class="{'mx-[20rpx]': swiperStyle2}"> |
|
||||
<swiper v-if="diyComponent.swiper.control" class="swiper" :style="{ height: imgHeight }" autoplay="true" circular="true" @change="swiperChange" |
|
||||
:class="{ |
|
||||
'swiper-left': diyComponent.swiper.indicatorAlign == 'left', |
|
||||
'swiper-right': diyComponent.swiper.indicatorAlign == 'right', |
|
||||
'ns-indicator-dots': diyComponent.swiper.indicatorStyle == 'style-2' |
|
||||
}" |
|
||||
:previous-margin="swiperStyle2 ? 0 : '36rpx'" :next-margin="swiperStyle2 ? 0 : '36rpx'" |
|
||||
:interval="diyComponent.swiper.interval * 1000" :indicator-dots="isShowDots" |
|
||||
:indicator-color="diyComponent.swiper.indicatorColor" :indicator-active-color="diyComponent.swiper.indicatorActiveColor"> |
|
||||
<swiper-item class="swiper-item" v-for="(item,index) in diyComponent.swiper.list" :key="item.id" :style="swiperWarpCss"> |
|
||||
<view @click="diyStore.toRedirect(item.link)"> |
|
||||
<view class="item" :style="{height: imgHeight}"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="scaleToFill" :style="swiperWarpCss" :class="['w-full h-full',{'swiper-animation': swiperIndex != index}]" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" :style="swiperWarpCss" mode="scaleToFill" :class="['w-full h-full',{'swiper-animation': swiperIndex != index}]" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
</swiper-item> |
|
||||
</swiper> |
|
||||
<!-- #ifdef MP-WEIXIN --> |
|
||||
<view v-if="diyComponent.swiper.list.length > 1" :class="[ |
|
||||
'swiper-dot-box', |
|
||||
{ 'straightLine': diyComponent.swiper.indicatorStyle == 'style-2' }, |
|
||||
{ 'swiper-left': diyComponent.swiper.indicatorAlign == 'left' }, |
|
||||
{ 'swiper-right': diyComponent.swiper.indicatorAlign == 'right' } |
|
||||
]"> |
|
||||
<view v-for="(numItem, numIndex) in diyComponent.swiper.list" :key="numIndex" :class="['swiper-dot', { active: numIndex == swiperIndex }]" :style="[numIndex == swiperIndex ? { backgroundColor: diyComponent.swiper.indicatorActiveColor } : { backgroundColor: diyComponent.swiper.indicatorColor }]"></view> |
|
||||
</view> |
|
||||
<!-- #endif --> |
|
||||
</view> |
|
||||
|
|
||||
<!-- 分类展开 --> |
|
||||
<u-popup :safeAreaInsetTop="true" :show="tabAllPopup" mode="top" @close="tabAllPopup = false"> |
|
||||
<view class="text-sm px-[30rpx] pt-3" :style="{'padding-top':(menuButtonInfo.top+'px')}">全部分类</view> |
|
||||
<view class="flex flex-wrap pl-[30rpx] pt-[30rpx]"> |
|
||||
<view @click="changeData({ source : 'home' },-1)" :class="['px-[26rpx] border-[2rpx] border-solid border-transparent h-[60rpx] mr-[30rpx] mb-[30rpx] flex items-center justify-center bg-[#F4F4F4] rounded-[8rpx] text-xs', { 'tab-select-popup': currTabIndex == -1 }]"> |
|
||||
首页 |
|
||||
</view> |
|
||||
<text @click="changeData(item,index)" v-for="(item, index) in diyComponent.tab.list" :key="index" |
|
||||
:class="['px-[26rpx] border-[2rpx] border-solid border-transparent h-[60rpx] mr-[30rpx] mb-[30rpx] flex items-center justify-center bg-[#F4F4F4] rounded-[8rpx] text-xs', { 'tab-select-popup': index == currTabIndex }]"> |
|
||||
{{ item.text }} |
|
||||
</text> |
|
||||
</view> |
|
||||
</u-popup> |
|
||||
</view> |
|
||||
|
|
||||
<!-- 展示微页面数据 --> |
|
||||
<template v-if="currentSource == 'diy_page'"> |
|
||||
|
|
||||
<view class="child-diy-template-wrap bg-index"> |
|
||||
|
|
||||
<diy-group :data="diyPageData"></diy-group> |
|
||||
|
|
||||
</view> |
|
||||
</template> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 轮播搜索 |
|
||||
import { ref, reactive, computed, watch, onMounted, nextTick, getCurrentInstance } from 'vue'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import diyGroup from '@/addon/components/diy/group/index.vue' |
|
||||
import { getDiyInfo } from '@/app/api/diy'; |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount', 'global']); |
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
const moduleHeight:any = ref('') |
|
||||
|
|
||||
const setModuleLocation = ()=> { |
|
||||
nextTick(() => { |
|
||||
setTimeout(()=>{ |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.fixed-wrap').boundingClientRect((data:any) => { |
|
||||
moduleHeight.value = (data.height || 0) + 'px'; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const fixedStyleBg = ref(false); |
|
||||
const fixedStyle = computed(()=>{ |
|
||||
if (diyStore.mode == 'decorate') return ''; |
|
||||
var style = ''; |
|
||||
// #ifdef H5 |
|
||||
if(props.global.topStatusBar.isShow && props.global.topStatusBar.style == 'style-4') { |
|
||||
style += 'top:' + diyStore.topTabarHeight + 'px;'; |
|
||||
} |
|
||||
// #endif |
|
||||
if(diyComponent.value.positionWay == 'fixed') { |
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ |
|
||||
menuButtonInfo = uni.getMenuButtonBoundingClientRect(); |
|
||||
if(props.global.topStatusBar.isShow) { |
|
||||
style += 'top:' + diyStore.topTabarHeight + 'px;'; |
|
||||
} |
|
||||
// #endif |
|
||||
|
|
||||
fixedStyleBg.value = false; |
|
||||
if (diyStore.scrollTop > 20) { |
|
||||
let str = diyComponent.value.fixedBgColor; |
|
||||
let arr = str.split(','); |
|
||||
let num = diyComponent.value.fixedBgColor ? parseInt(arr[arr.length-1]) : 0; |
|
||||
if(!diyComponent.value.fixedBgColor || num == 0 ){ |
|
||||
fixedStyleBg.value = true; |
|
||||
}else{ |
|
||||
fixedStyleBg.value = false; |
|
||||
style += 'background-color:' + diyComponent.value.fixedBgColor + ';'; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const getTabColor = (flag:any)=>{ |
|
||||
let color = ''; |
|
||||
if(flag){ |
|
||||
color = diyComponent.value.tab.selectColor; |
|
||||
if(diyComponent.value.positionWay == 'fixed' && diyStore.scrollTop > 20) { |
|
||||
color = diyComponent.value.tab.fixedSelectColor; |
|
||||
} |
|
||||
}else{ |
|
||||
color = diyComponent.value.tab.noColor; |
|
||||
if(diyComponent.value.positionWay == 'fixed' && diyStore.scrollTop > 20) { |
|
||||
color = diyComponent.value.tab.fixedNoColor; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return color; |
|
||||
} |
|
||||
|
|
||||
const isShowSearchPlaceholder = computed(()=> { |
|
||||
let flag = true; |
|
||||
for (let i = 0; i < diyComponent.value.search.hotWord.list.length; i++) { |
|
||||
let item = diyComponent.value.search.hotWord.list[i]; |
|
||||
if (item.text) { |
|
||||
flag = false; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
return flag; |
|
||||
}) |
|
||||
|
|
||||
// 背景渐变 |
|
||||
const bgImgBoxStyle = computed(()=>{ |
|
||||
var style = ''; |
|
||||
let str = props.global.pageStartBgColor ? props.global.pageStartBgColor : 'rgba(255,255,255,1)'; |
|
||||
if(str.indexOf('(') > -1) { |
|
||||
let arr = str.split('(')[1].split(')')[0].split(','); |
|
||||
if (diyComponent.value.bgGradient == true) { |
|
||||
style += `background: linear-gradient(rgba(${arr[0]}, ${arr[1]}, ${arr[2]}, 0) 65%, rgba(${arr[0]}, ${arr[1]}, ${arr[2]}, 0.6) 70%, rgba(${arr[0]}, ${arr[1]}, ${arr[2]}, 0.85) 80%, rgba(${arr[0]}, ${arr[1]}, ${arr[2]}, 0.95) 90%, rgb(${arr[0]}, ${arr[1]}, ${arr[2]}, 1) 100%);`; |
|
||||
} |
|
||||
}else{ |
|
||||
style += `background: (${str});`; |
|
||||
} |
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
// 轮播样式二 |
|
||||
const swiperStyle2 = computed(()=>{ |
|
||||
var style = false; |
|
||||
style = diyComponent.value.swiper.swiperStyle == 'style-2' ? true : false; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const imgHeight = computed(() => { |
|
||||
return (diyComponent.value.swiper.imageHeight * 2) + 'rpx'; |
|
||||
}) |
|
||||
|
|
||||
const swiperIndex = ref(0); |
|
||||
|
|
||||
const swiperChange = e => { |
|
||||
swiperIndex.value = e.detail.current; |
|
||||
}; |
|
||||
|
|
||||
const swiperWarpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if (diyComponent.value.swiper.topRounded) style += 'border-top-left-radius:' + diyComponent.value.swiper.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.swiper.topRounded) style += 'border-top-right-radius:' + diyComponent.value.swiper.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.swiper.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.swiper.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.swiper.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.swiper.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const currTabIndex = ref(-1) |
|
||||
|
|
||||
const currentSource = ref('') |
|
||||
|
|
||||
const changeData = (item:any,index:any)=> { |
|
||||
if (diyStore.mode == 'decorate') return false; |
|
||||
currentSource.value = item.source; |
|
||||
currTabIndex.value = index; |
|
||||
if(item.source == 'home'){ |
|
||||
|
|
||||
// 首页 |
|
||||
diyStore.topFixedStatus = 'home' |
|
||||
|
|
||||
}else if (item.source == 'diy_page') { |
|
||||
|
|
||||
// 查询微页面数据 |
|
||||
diyStore.topFixedStatus = 'diy' |
|
||||
getDiyInfoFn(item.diy_id); |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
let tabAllPopup = ref(false); |
|
||||
let menuButtonInfo:any = {}; |
|
||||
let navbarInnerStyle = ref('') |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'CarouselSearch') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
|
|
||||
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容) |
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ |
|
||||
if(diyComponent.value.positionWay == 'fixed') { |
|
||||
menuButtonInfo = uni.getMenuButtonBoundingClientRect(); |
|
||||
// 导航栏内部盒子的样式 |
|
||||
// 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离 |
|
||||
// 如果是各家小程序,导航栏内部的宽度需要减少右边胶囊的宽度 |
|
||||
if(props.global.topStatusBar.isShow == false) { |
|
||||
let rightButtonWidth = menuButtonInfo.width ? menuButtonInfo.width * 2 + 'rpx' : '70rpx'; |
|
||||
navbarInnerStyle.value += 'padding-right:calc(' + rightButtonWidth + ' + 30rpx);'; |
|
||||
navbarInnerStyle.value += 'padding-top:' + menuButtonInfo.top + 'px;'; |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
// #endif |
|
||||
|
|
||||
}); |
|
||||
|
|
||||
const refresh = ()=> { |
|
||||
setModuleLocation(); |
|
||||
changeData({ source : 'home' },-1) |
|
||||
diyComponent.value.swiper.list.forEach((item : any) => { |
|
||||
if (item.imageUrl == '') { |
|
||||
item.imgWidth = 690; |
|
||||
item.imgHeight = 330; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
const diyPageData = reactive({ |
|
||||
pageMode: 'diy', |
|
||||
title: '', |
|
||||
global: <any>{}, |
|
||||
value: [] |
|
||||
}) |
|
||||
|
|
||||
const getDiyInfoFn = (id:any) => { |
|
||||
if(!id){ |
|
||||
diyPageData.pageMode = 'diy'; |
|
||||
diyPageData.title = ''; |
|
||||
diyPageData.global = {}; |
|
||||
diyPageData.value = []; |
|
||||
return; |
|
||||
} |
|
||||
getDiyInfo({ |
|
||||
id |
|
||||
}).then((res : any) => { |
|
||||
if (res.data.value) { |
|
||||
let data = res.data; |
|
||||
diyPageData.pageMode = data.mode; |
|
||||
diyPageData.title = data.title; |
|
||||
|
|
||||
let sources = JSON.parse(data.value); |
|
||||
diyPageData.global = sources.global; |
|
||||
diyPageData.global.topStatusBar.isShow = false; // 子页面不需要展示顶部导航栏 |
|
||||
diyPageData.global.bottomTabBarSwitch = false; // 子页面不需要展示底部导航 |
|
||||
diyPageData.value = sources.value; |
|
||||
|
|
||||
diyPageData.value.forEach((item, index) => { |
|
||||
item.pageStyle = ''; |
|
||||
if(item.pageStartBgColor) { |
|
||||
if (item.pageStartBgColor && item.pageEndBgColor) item.pageStyle += `background:linear-gradient(${item.pageGradientAngle},${item.pageStartBgColor},${item.pageEndBgColor});`; |
|
||||
else item.pageStyle += 'background-color:' + item.pageStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if (item.margin) { |
|
||||
if (item.margin.top > 0) { |
|
||||
item.pageStyle += 'padding-top:' + item.margin.top * 2 + 'rpx' + ';'; |
|
||||
} |
|
||||
item.pageStyle += 'padding-bottom:' + item.margin.bottom * 2 + 'rpx' + ';'; |
|
||||
item.pageStyle += 'padding-right:' + item.margin.both * 2 + 'rpx' + ';'; |
|
||||
item.pageStyle += 'padding-left:' + item.margin.both * 2 + 'rpx' + ';'; |
|
||||
} |
|
||||
}); |
|
||||
uni.setNavigationBarTitle({ |
|
||||
title: diyPageData.title |
|
||||
}) |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
// 轮播指示器 |
|
||||
let isShowDots = ref(true) |
|
||||
// #ifdef H5 |
|
||||
isShowDots.value = true; |
|
||||
// #endif |
|
||||
|
|
||||
// #ifdef MP-WEIXIN |
|
||||
isShowDots.value = false; |
|
||||
// #endif |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.goods-carousel-search-wrap{ |
|
||||
.bg-img{ |
|
||||
position: absolute; |
|
||||
width: 100%; |
|
||||
top: 0; |
|
||||
bottom: 0; |
|
||||
z-index: 0; |
|
||||
-webkit-filter: blur(0); |
|
||||
filter: blur(0); |
|
||||
overflow: hidden; |
|
||||
uni-image, image{ |
|
||||
-webkit-filter: blur(15px); |
|
||||
filter: blur(15px); |
|
||||
-webkit-transform: scale(1.5); |
|
||||
transform: scale(1.5); |
|
||||
} |
|
||||
.bg-img-box{ |
|
||||
position: absolute; |
|
||||
top: 0; |
|
||||
right: 0; |
|
||||
bottom: 0; |
|
||||
left: 0; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.fixed-wrap { |
|
||||
&.fixed { |
|
||||
position: fixed; |
|
||||
left: 0; |
|
||||
right: 0; |
|
||||
top: 0; |
|
||||
z-index: 991; |
|
||||
transition: background .3s; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.diy-search-wrap{ |
|
||||
display: flex; |
|
||||
position: relative; |
|
||||
align-items: center; |
|
||||
padding:20rpx; |
|
||||
.img-wrap{ |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: center; |
|
||||
width: 140rpx; |
|
||||
height: 60rpx; |
|
||||
margin-right: 20rpx; |
|
||||
image{ |
|
||||
width: 100%; |
|
||||
height:100%; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.search-content { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
padding: 0 40rpx; |
|
||||
border-radius: 50rpx; |
|
||||
background-color: rgba(255,255,255,.2); |
|
||||
flex: 1; |
|
||||
position: relative; |
|
||||
input, .uni-input { |
|
||||
box-sizing: border-box; |
|
||||
display: block; |
|
||||
height: 64rpx; |
|
||||
line-height: 68rpx; |
|
||||
width: 100%; |
|
||||
padding-right: 20rpx; |
|
||||
color: #fff; |
|
||||
background: none; |
|
||||
} |
|
||||
.iconfont { |
|
||||
font-size: 30rpx; |
|
||||
font-weight: bold; |
|
||||
color: #fff; |
|
||||
} |
|
||||
.swiper-wrap{ |
|
||||
position: absolute; |
|
||||
width:80%; |
|
||||
height: 64rpx; |
|
||||
line-height: 64rpx; |
|
||||
color:#fff; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
.tab-list-wrap { |
|
||||
.scroll-wrap { |
|
||||
left: 0; |
|
||||
right: 0; |
|
||||
z-index: 5; |
|
||||
width: 100%; |
|
||||
white-space: nowrap; |
|
||||
box-sizing: border-box; |
|
||||
padding: 20rpx 80rpx 20rpx 20rpx; |
|
||||
} |
|
||||
.scroll-item { |
|
||||
display: inline-block; |
|
||||
text-align: center; |
|
||||
vertical-align: top; |
|
||||
width: auto; |
|
||||
position: relative; |
|
||||
padding: 0 20rpx; |
|
||||
|
|
||||
.name { |
|
||||
font-size: 28rpx; |
|
||||
color: #333; |
|
||||
line-height: 38rpx; |
|
||||
margin-bottom: 10rpx; |
|
||||
} |
|
||||
|
|
||||
&.active { |
|
||||
position: relative; |
|
||||
.name { |
|
||||
font-size: 32rpx; |
|
||||
line-height: 38rpx; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
.line{ |
|
||||
position: absolute; |
|
||||
bottom: 0; |
|
||||
width: 34rpx; |
|
||||
height: 4rpx; |
|
||||
border-radius: 29%; |
|
||||
left: 50%; |
|
||||
transform: translateX(-50%); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
.tab-btn{ |
|
||||
font-size: 34rpx; |
|
||||
/* #ifdef H5 */ |
|
||||
top: 22rpx; |
|
||||
right: 20rpx; |
|
||||
line-height: 1; |
|
||||
color: #fff; |
|
||||
&::after{ |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
top: 6rpx; |
|
||||
bottom: -2rpx; |
|
||||
left: -14rpx; |
|
||||
width: 4rpx; |
|
||||
background: linear-gradient( 180deg, #FFFFFF 16%, rgba(255,255,255,0) 92%); |
|
||||
} |
|
||||
/* #endif */ |
|
||||
/* #ifdef MP-WEIXIN */ |
|
||||
top: 24rpx; |
|
||||
right: 20rpx; |
|
||||
color: #fff; |
|
||||
&::after{ |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
top: 2rpx; |
|
||||
bottom: 0; |
|
||||
left: -16rpx; |
|
||||
width: 4rpx; |
|
||||
background: linear-gradient( 180deg, #FFFFFF 16%, rgba(255,255,255,0) 92%); |
|
||||
} |
|
||||
/* #endif */ |
|
||||
} |
|
||||
} |
|
||||
.tab-select-popup{ |
|
||||
color: var(--primary-color); |
|
||||
border-color: var(--primary-color); |
|
||||
background-color: var(--primary-color-light); |
|
||||
} |
|
||||
.swiper-animation{ |
|
||||
transform: scale(0.94, 0.94); |
|
||||
transition-duration: 0.3s; |
|
||||
transition-timing-function: ease; |
|
||||
} |
|
||||
// 轮播指示器 |
|
||||
.swiper-right :deep(.uni-swiper-dots-horizontal) { |
|
||||
right: 80rpx; |
|
||||
display: flex; |
|
||||
justify-content: flex-end; |
|
||||
transform: translate(0); |
|
||||
} |
|
||||
.swiper-left :deep(.uni-swiper-dots-horizontal) { |
|
||||
left: 80rpx; |
|
||||
transform: translate(0); |
|
||||
} |
|
||||
.swiper.ns-indicator-dots :deep(.uni-swiper-dot) { |
|
||||
width: 18rpx; |
|
||||
height: 6rpx; |
|
||||
border-radius: 4rpx; |
|
||||
} |
|
||||
.swiper.ns-indicator-dots :deep(.uni-swiper-dot-active) { |
|
||||
width: 36rpx; |
|
||||
} |
|
||||
.swiper-dot-box { |
|
||||
position: absolute; |
|
||||
bottom: 20rpx; |
|
||||
width: 100%; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: center; |
|
||||
padding: 0 80rpx 8rpx; |
|
||||
box-sizing: border-box; |
|
||||
|
|
||||
&.swiper-left { |
|
||||
justify-content: flex-start; |
|
||||
} |
|
||||
|
|
||||
&.swiper-right { |
|
||||
justify-content: flex-end; |
|
||||
} |
|
||||
|
|
||||
.swiper-dot { |
|
||||
background-color: #b2b2b2; |
|
||||
width: 15rpx; |
|
||||
border-radius: 50%; |
|
||||
height: 15rpx; |
|
||||
margin: 8rpx; |
|
||||
} |
|
||||
|
|
||||
&.straightLine { |
|
||||
.swiper-dot { |
|
||||
width: 18rpx; |
|
||||
height: 6rpx; |
|
||||
border-radius: 4rpx; |
|
||||
|
|
||||
&.active { |
|
||||
width: 36rpx; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,113 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :class="['float-btn flex flex-col z-1000 items-center px-[24rpx] fixed', diyComponent.bottomPosition, diyStore.mode == 'decorate' ? 'float-btn-border' : '']" :style="floatBtnWrapCss"> |
|
||||
<view v-for="(item,index) in diyComponent.list" :key="index" @click="diyStore.toRedirect(item.link)" :class="{'flex items-center justify-center' : true, 'mb-[20rpx]': diyComponent.list.length != index+1 }" :style="floatBtnItemCss"> |
|
||||
<image v-if="item && item.imageUrl" :style="floatBtnItemCss" :src="img(item.imageUrl)" mode="aspectFit"></image> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFit" :style="floatBtnItemCss"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 浮动按钮组件 |
|
||||
import { computed, watch } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const floatBtnItemCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'width:' + diyComponent.value.imageSize * 2 + 'rpx;'; |
|
||||
style += 'height:' + diyComponent.value.imageSize * 2 + 'rpx;'; |
|
||||
style += 'border-radius:' + diyComponent.value.aroundRadius * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const floatBtnWrapCss = computed(() => { |
|
||||
let style = ''; |
|
||||
if(diyComponent.value.offset){ |
|
||||
if(diyComponent.value.bottomPosition == 'lowerRight' || diyComponent.value.bottomPosition == 'lowerLeft'){ |
|
||||
style += 'padding-bottom:'+ diyComponent.value.offset * 2 + 'rpx;'; |
|
||||
}else if(diyComponent.value.bottomPosition == 'upperRight' || diyComponent.value.bottomPosition == 'upperLeft'){ |
|
||||
style += 'padding-top:'+ diyComponent.value.offset * 2 + 'rpx;'; |
|
||||
} |
|
||||
} |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.float-btn{ |
|
||||
&.decorate-position.upperRight,&.decorate-position.lowerRight { |
|
||||
align-items: flex-end; |
|
||||
} |
|
||||
&.decorate-position.upperLeft,&.decorate-position.lowerLeft { |
|
||||
align-items: baseline; |
|
||||
} |
|
||||
&.upperLeft { |
|
||||
top: 100rpx; |
|
||||
left: 30rpx; |
|
||||
} |
|
||||
|
|
||||
&.upperRight { |
|
||||
top: 100rpx; |
|
||||
right: 30rpx; |
|
||||
} |
|
||||
|
|
||||
&.lowerLeft { |
|
||||
bottom: 160rpx; |
|
||||
left: 30rpx; |
|
||||
padding-bottom: constant(safe-area-inset-bottom); |
|
||||
/*兼容 IOS<11.2*/ |
|
||||
padding-bottom: env(safe-area-inset-bottom); |
|
||||
/*兼容 IOS>11.2*/ |
|
||||
} |
|
||||
|
|
||||
&.lowerRight { |
|
||||
bottom: 160rpx; |
|
||||
right: 30rpx; |
|
||||
padding-bottom: constant(safe-area-inset-bottom); |
|
||||
/*兼容 IOS<11.2*/ |
|
||||
padding-bottom: env(safe-area-inset-bottom); |
|
||||
/*兼容 IOS>11.2*/ |
|
||||
} |
|
||||
} |
|
||||
.z-1000{ |
|
||||
z-index: 1000; |
|
||||
} |
|
||||
.float-btn-border{ |
|
||||
border: 4rpx dashed var(--primary-color); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,257 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view class="diy-graphic-nav relative"> |
|
||||
<view v-if="diyComponent.layout == 'vertical'" class="graphic-nav"> |
|
||||
<view class="graphic-nav-item" v-for="(item, index) in diyComponent.list" :key="item.id"> |
|
||||
|
|
||||
<view @click="diyStore.toRedirect(item.link)" :class="['flex items-center justify-between py-3 px-4', index == 0 ? 'border-t-0':'border-t']"> |
|
||||
|
|
||||
<view class="graphic-img relative flex items-center w-10 h-10 mr-[20rpx]" |
|
||||
v-if="diyComponent.mode != 'text'" |
|
||||
:style="{ width: diyComponent.imageSize * 2 + 'rpx', height: diyComponent.imageSize * 2 + 'rpx' }"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="aspectFill" |
|
||||
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFill" |
|
||||
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/> |
|
||||
|
|
||||
<text v-if="item.label.control" |
|
||||
class="tag absolute -top-[10rpx] -right-[24rpx] text-white rounded-[24rpx] rounded-bl-none transform scale-80 py-1 px-2 text-xs" |
|
||||
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }"> |
|
||||
{{ item.label.text }} |
|
||||
</text> |
|
||||
</view> |
|
||||
|
|
||||
<text v-if="diyComponent.mode != 'img'" class="graphic-text w-full truncate leading-normal" |
|
||||
:style="{ fontSize: diyComponent.font.size * 2 + 'rpx', fontWeight: diyComponent.font.weight, color: diyComponent.font.color }"> |
|
||||
{{ item.title }} |
|
||||
</text> |
|
||||
<u-icon name="arrow-right" color="#999999" size="12"></u-icon> |
|
||||
|
|
||||
</view> |
|
||||
|
|
||||
</view> |
|
||||
|
|
||||
</view> |
|
||||
<swiper v-else-if="diyComponent.layout == 'horizontal' && diyComponent.showStyle == 'pageSlide'" |
|
||||
class="graphic-nav box-border relative" circular :indicator-dots="false" |
|
||||
:style="{ height: swiperHeight }" @change="swiperChange"> |
|
||||
<swiper-item class="graphic-nav-wrap flex flex-wrap" v-for="(numItem, numIndex) in Math.ceil(diyComponent.list.length / (diyComponent.pageCount * diyComponent.rowCount))"> |
|
||||
|
|
||||
<template v-for="(item, index) in diyComponent.list"> |
|
||||
|
|
||||
<view class="graphic-nav-item" :class="[diyComponent.mode]" :key="item.id" v-if="swiperCondition(index,numItem)" :style="{ width: 100 / diyComponent.rowCount + '%' }"> |
|
||||
|
|
||||
<view @click="diyStore.toRedirect(item.link)" class="flex flex-col items-center box-border py-2"> |
|
||||
|
|
||||
<view class="graphic-img relative flex items-center justify-center w-10 h-10" |
|
||||
v-if="diyComponent.mode != 'text'" |
|
||||
:style="{ width: diyComponent.imageSize * 2 + 'rpx', height: diyComponent.imageSize * 2 + 'rpx' }"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="aspectFill" |
|
||||
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFill" |
|
||||
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/> |
|
||||
|
|
||||
<text |
|
||||
class="tag absolute -top-[10rpx] -right-[24rpx] text-white rounded-[24rpx] rounded-bl-none transform scale-80 py-1 px-2 text-xs" |
|
||||
v-if="item.label.control" |
|
||||
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }"> |
|
||||
{{ item.label.text }} |
|
||||
</text> |
|
||||
</view> |
|
||||
|
|
||||
<text v-if="diyComponent.mode != 'img'" |
|
||||
class="graphic-text w-full text-center truncate leading-normal" |
|
||||
:class="{ 'pt-1.5' : diyComponent.mode != 'text' }" |
|
||||
:style="{ fontSize: diyComponent.font.size * 2 + 'rpx', fontWeight: diyComponent.font.weight, color: diyComponent.font.color }"> |
|
||||
{{ item.title }} |
|
||||
</text> |
|
||||
</view> |
|
||||
|
|
||||
</view> |
|
||||
</template> |
|
||||
</swiper-item> |
|
||||
</swiper> |
|
||||
|
|
||||
<scroll-view v-else :scroll-x="diyComponent.showStyle == 'singleSlide'" :class="['graphic-nav','graphic-nav-' + diyComponent.showStyle]" class=" py-[10rpx]"> |
|
||||
<!-- #ifdef MP --> |
|
||||
<view class="uni-scroll-view-content"> |
|
||||
<!-- #endif --> |
|
||||
|
|
||||
<view class="graphic-nav-item" :class="{'flex-shrink-0' : diyComponent.showStyle == 'singleSlide'}" |
|
||||
v-for="(item, index) in diyComponent.list" :key="item.id" |
|
||||
:style="{ width: 100 / diyComponent.rowCount + '%' }"> |
|
||||
|
|
||||
<view @click="diyStore.toRedirect(item.link)" class="flex flex-col items-center box-border py-2"> |
|
||||
<view class="graphic-img relative flex items-center justify-center w-10 h-10" |
|
||||
v-if="diyComponent.mode != 'text'" |
|
||||
:style="{ width: diyComponent.imageSize * 2 + 'rpx', height: diyComponent.imageSize * 2 + 'rpx' }"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="aspectFill" |
|
||||
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="aspectFill" |
|
||||
:style="{ maxWidth: diyComponent.imageSize * 2 + 'rpx', maxHeight: diyComponent.imageSize * 2 + 'rpx', borderRadius: diyComponent.aroundRadius * 2 + 'rpx' }"/> |
|
||||
<text |
|
||||
:class="['tag absolute -top-[10rpx] -right-[24rpx] text-white rounded-[24rpx] rounded-bl-none transform scale-80 py-1 px-2 text-xs']" |
|
||||
v-if="item.label.control" |
|
||||
:style="{ color: item.label.textColor, backgroundImage: 'linear-gradient(' + item.label.bgColorStart + ',' + item.label.bgColorEnd + ')' }"> |
|
||||
{{ item.label.text }} |
|
||||
</text> |
|
||||
</view> |
|
||||
<text v-if="diyComponent.mode != 'img'" |
|
||||
class="graphic-text w-full text-center truncate leading-normal" |
|
||||
:class="{ 'pt-1.5' : diyComponent.mode != 'text' }" |
|
||||
:style="{ fontSize: diyComponent.font.size * 2 + 'rpx', fontWeight: diyComponent.font.weight, color: diyComponent.font.color }"> |
|
||||
{{ item.title }} |
|
||||
</text> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<!-- #ifdef MP --> |
|
||||
</view> |
|
||||
<!-- #endif --> |
|
||||
|
|
||||
</scroll-view> |
|
||||
|
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
// 图文导航 |
|
||||
import { ref,computed, watch, onMounted, nextTick,getCurrentInstance } from 'vue'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
const swiperIndex = ref(0); |
|
||||
|
|
||||
const swiperChange = e => { |
|
||||
swiperIndex.value = e.detail.current; |
|
||||
}; |
|
||||
|
|
||||
const swiperCondition = (index, numItem) => { |
|
||||
let count = diyComponent.value.pageCount * diyComponent.value.rowCount; |
|
||||
let result = true; |
|
||||
|
|
||||
// #ifdef MP-WEIXIN |
|
||||
result = index >= [(numItem) * (count)] && index < [(numItem + 1) * (count)]; |
|
||||
// #endif |
|
||||
|
|
||||
// #ifdef H5 |
|
||||
result = index >= [(numItem - 1) * (count)] && index < [numItem * (count)]; |
|
||||
// #endif |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
const swiperHeight = ref(''); |
|
||||
|
|
||||
const handleData = () => { |
|
||||
if(diyComponent.value.layout == 'horizontal' && diyComponent.value.showStyle == 'pageSlide') { |
|
||||
var height = 0; |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.graphic-nav-item').boundingClientRect((data: any) => { |
|
||||
height = data.height * diyComponent.value.pageCount; |
|
||||
swiperHeight.value = (height * 2) + 'rpx'; |
|
||||
}).exec(); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'GraphicNav') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = () => { |
|
||||
nextTick(() => { |
|
||||
handleData() |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.diy-graphic-nav').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style> |
|
||||
/* 固定显示 */ |
|
||||
.graphic-nav-fixed>>>.uni-scroll-view-content { |
|
||||
display: flex; |
|
||||
flex-wrap: wrap; |
|
||||
} |
|
||||
|
|
||||
/* 单行滑动 */ |
|
||||
.graphic-nav-singleSlide>>>.uni-scroll-view-content { |
|
||||
display: flex; |
|
||||
} |
|
||||
</style> |
|
||||
<style lang="scss" scoped> |
|
||||
</style> |
|
||||
@ -1,44 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"></view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 辅助空白 |
|
||||
import { computed, watch } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'height:' + diyComponent.value.height * 2 + 'rpx;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,40 +0,0 @@ |
|||||
<template> |
|
||||
<view class="horz-line-wrap"> |
|
||||
<view v-if="diyStore.mode == 'decorate'" class="h-[30rpx]"></view> |
|
||||
<view :style="warpCss"></view> |
|
||||
<view v-if="diyStore.mode == 'decorate'" class="h-[30rpx]"></view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 辅助线 |
|
||||
import { computed, watch } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'border-top:' + (diyComponent.value.borderWidth * 2) + 'rpx ' + diyComponent.value.borderStyle + ' ' + diyComponent.value.borderColor + ';'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,91 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view class="simple-graph-wrap overflow-hidden relative leading-0"> |
|
||||
<image v-if="diyComponent.imageUrl" :style="itemCss" :src="img(diyComponent.imageUrl)" mode="widthFix" :show-menu-by-longpress="true" class="w-full"/> |
|
||||
<image v-else :style="itemCss" :src="img('static/resource/images/diy/figure.png')" mode="widthFix" :show-menu-by-longpress="true" class="w-full"/> |
|
||||
|
|
||||
<template v-if="diyStore.mode != 'decorate'"> |
|
||||
<!-- 热区功能 --> |
|
||||
<view @click="diyStore.toRedirect(mapItem.link)" class="absolute" v-for="(mapItem, mapIndex) in diyComponent.heatMapData" |
|
||||
:key="mapIndex" :style="{ |
|
||||
width: mapItem.width + '%', |
|
||||
height: mapItem.height + '%', |
|
||||
left: mapItem.left + '%', |
|
||||
top: mapItem.top + '%' |
|
||||
}"></view> |
|
||||
|
|
||||
</template> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 热区 |
|
||||
import { computed, watch, onMounted } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const itemCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'height:' + diyComponent.value.imgHeight + ';'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'HotArea') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
}); |
|
||||
|
|
||||
const refresh = () => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
// 装修模式下设置默认图 |
|
||||
if (diyComponent.value.imageUrl == '') { |
|
||||
diyComponent.value.imgWidth = 690; |
|
||||
diyComponent.value.imgHeight = 330; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
</style> |
|
||||
@ -1,140 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view class="diy-image-ads"> |
|
||||
<view v-if="diyComponent.list.length == 1" class="leading-0 overflow-hidden" :style="swiperWarpCss"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.list[0].link)"> |
|
||||
<image v-if="diyComponent.list[0].imageUrl" :src="img(diyComponent.list[0].imageUrl)" :style="{height: imgHeight}" mode="heightFix" class="!w-full" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" :style="{height: imgHeight}" mode="heightFix" class="!w-full" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<swiper v-else class="swiper" :style="{ height: imgHeight }" autoplay="true" circular="true" @change="swiperChange"> |
|
||||
<swiper-item class="swiper-item" v-for="(item) in diyComponent.list" :key="item.id" :style="swiperWarpCss"> |
|
||||
<view @click="diyStore.toRedirect(item.link)"> |
|
||||
<view class="item" :style="{height: imgHeight}"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="scaleToFill" class="w-full h-full" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="scaleToFill" class="w-full h-full" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
</swiper-item> |
|
||||
</swiper> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
// 图片广告 |
|
||||
import { ref,computed, watch, onMounted, nextTick,getCurrentInstance } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
const swiperWarpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
const imgHeight = computed(() => { |
|
||||
return (diyComponent.value.imageHeight * 2) + 'rpx'; |
|
||||
}) |
|
||||
|
|
||||
const swiperIndex = ref(0); |
|
||||
|
|
||||
const swiperChange = e => { |
|
||||
swiperIndex.value = e.detail.current; |
|
||||
}; |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'ImageAds') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = () => { |
|
||||
// 装修模式下设置默认图 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
diyComponent.value.list.forEach((item : any) => { |
|
||||
if (item.imageUrl == '') { |
|
||||
item.imgWidth = 690; |
|
||||
item.imgHeight = 330; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
nextTick(() => { |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.diy-image-ads').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
</style> |
|
||||
@ -1,185 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view class="pt-[34rpx] member-info"> |
|
||||
<!-- #ifdef MP-WEIXIN --> |
|
||||
<!-- 解决fixed定位后导航栏塌陷的问题 --> |
|
||||
<view :style="navbarInnerStyle"></view> |
|
||||
<!-- #endif --> |
|
||||
<view v-if="info" class="flex ml-[32rpx] mr-[52rpx] items-center relative"> |
|
||||
<!-- 唤起获取微信 --> |
|
||||
<u-avatar :src="img(info.headimg)" size="55" leftIcon="none" @click="clickAvatar"></u-avatar> |
|
||||
<view class="ml-[22rpx]"> |
|
||||
<view class="text-[#222222] flex pr-[50rpx] flex-wrap items-center"> |
|
||||
<view class="text-[#222222] truncate max-w-[320rpx] font-bold text-lg mr-[16rpx]" :style="{ color : diyComponent.textColor }">{{ info.nickname }}</view> |
|
||||
</view> |
|
||||
<view class="text-[#696B70] text-[24rpx] mt-[10rpx]" :style="{ color : diyComponent.textColor }">UID:{{ info.member_no }}</view> |
|
||||
</view> |
|
||||
<view class="set-icon flex items-center absolute right-0 top-2"> |
|
||||
<view @click="redirect({ url: '/app/pages/setting/index' })"> |
|
||||
<text class="nc-iconfont nc-icon-shezhiV6xx-1 text-[40rpx] ml-[10rpx]" :style="{ color : diyComponent.textColor }"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-else class="flex ml-[32rpx] mr-[52rpx] items-center relative" @click="toLogin"> |
|
||||
<u-avatar src="" size="55"></u-avatar> |
|
||||
<view class="ml-[22rpx]"> |
|
||||
<view class="text-[#222222] font-bold text-lg" :style="{ color : diyComponent.textColor }"> |
|
||||
{{ t('login') }}/{{ t('register') }} |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="set-icon flex items-center absolute right-0 top-2"> |
|
||||
<view @click="redirect({ url: '/app/pages/setting/index' })"> |
|
||||
<text class="nc-iconfont nc-icon-shezhiV6xx-1 text-[40rpx] ml-[10rpx]" :style="{ color : diyComponent.textColor }"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<view class="flex m-[30rpx] mb-0 py-[30rpx] items-center"> |
|
||||
<view class="flex-1 text-center"> |
|
||||
<view class="font-bold"> |
|
||||
<view @click="redirect({ url: info ? '/app/pages/member/balance' : '' })" :style="{ color : diyComponent.textColor }">{{ money }}</view> |
|
||||
</view> |
|
||||
<view class="text-sm mt-[10rpx]"> |
|
||||
<view @click="redirect({ url: info ? '/app/pages/member/balance' : '' })" :style="{ color : diyComponent.textColor }">{{ t('balance') }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="border-solid border-white border-l border-b-0 border-t-0 border-r-0 h-[60rpx]"></view> |
|
||||
<view class="flex-1 text-center"> |
|
||||
<view class="font-bold"> |
|
||||
<view @click="redirect({ url: info ? '/app/pages/member/point' : '' })" :style="{ color : diyComponent.textColor }">{{ parseInt(info?.point) || 0 }}</view> |
|
||||
</view> |
|
||||
<view class="text-sm mt-[10rpx]"> |
|
||||
<view @click="redirect({ url: info ? '/app/pages/member/point' : '' })" :style="{ color : diyComponent.textColor }">{{ t('point') }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<!-- #ifdef MP-WEIXIN --> |
|
||||
<information-filling ref="infoFill"></information-filling> |
|
||||
<!-- #endif --> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { computed, ref, watch } from 'vue' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import { useLogin } from '@/hooks/useLogin' |
|
||||
import { img, isWeixinBrowser, redirect, urlDeconstruction, moneyFormat } from '@/utils/common' |
|
||||
import { t } from '@/locale' |
|
||||
import { wechatSync } from '@/app/api/system' |
|
||||
import useDiyStore from '@/app/stores/diy' |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount','global']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
if (diyComponent.value.bgUrl) { |
|
||||
style += 'background-image:url(' + img(diyComponent.value.bgUrl) + ');'; |
|
||||
style += 'background-size: 100%;'; |
|
||||
style += 'background-repeat: no-repeat;'; |
|
||||
} |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
|
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
const memberStore = useMemberStore() |
|
||||
|
|
||||
// #ifdef H5 |
|
||||
const { query } = urlDeconstruction(location.href) |
|
||||
if (query.code && isWeixinBrowser()) { |
|
||||
wechatSync({ code: query.code }).then(res => { |
|
||||
memberStore.getMemberInfo() |
|
||||
}) |
|
||||
} |
|
||||
// #endif |
|
||||
|
|
||||
const info = computed(() => { |
|
||||
// 装修模式 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return { |
|
||||
headimg: '', |
|
||||
nickname: '昵称', |
|
||||
balance: 0, |
|
||||
point: 0, |
|
||||
money: 0, |
|
||||
member_no: 'NIU0000021' |
|
||||
} |
|
||||
} else { |
|
||||
return memberStore.info; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const money = computed(() => { |
|
||||
if (info.value) { |
|
||||
let m = parseFloat(info.value.balance) + parseFloat(info.value.money) |
|
||||
return moneyFormat(m.toString()); |
|
||||
} else { |
|
||||
return 0; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const toLogin = () => { |
|
||||
useLogin().setLoginBack({ url: '/app/pages/member/index' }) |
|
||||
} |
|
||||
|
|
||||
const infoFill = ref(false) |
|
||||
const clickAvatar = () => { |
|
||||
// #ifdef MP-WEIXIN |
|
||||
infoFill.value.show = true |
|
||||
// #endif |
|
||||
|
|
||||
// #ifdef H5 |
|
||||
if (isWeixinBrowser()) { |
|
||||
useLogin().getAuthCode('snsapi_userinfo') |
|
||||
} else { |
|
||||
redirect({ url: '/app/pages/member/personal' }) |
|
||||
} |
|
||||
// #endif |
|
||||
} |
|
||||
let menuButtonInfo = {}; |
|
||||
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容) |
|
||||
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ |
|
||||
menuButtonInfo = uni.getMenuButtonBoundingClientRect(); |
|
||||
// #endif |
|
||||
|
|
||||
// 导航栏内部盒子的样式 |
|
||||
const navbarInnerStyle = computed(() => { |
|
||||
let style = ''; |
|
||||
// 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离 |
|
||||
// #ifdef MP |
|
||||
if (props.global.topStatusBar.isShow == false) { |
|
||||
style += 'height:' + menuButtonInfo.height + 'px;'; |
|
||||
style += 'padding-top:' + menuButtonInfo.top + 'px;'; |
|
||||
} |
|
||||
// #endif |
|
||||
return style; |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
</style> |
|
||||
@ -1,220 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss" class="overflow-hidden" v-if="info && list && list.length"> |
|
||||
<view v-if="diyComponent.style == 'style-1'" class="rounded-t-[16rpx] flex items-center justify-between style-bg-1 py-[20rpx] px-[30rpx]"> |
|
||||
<view class="flex items-end"> |
|
||||
<image :src="img('static/resource/images/diy/member/VIP_02.png')" mode="aspectFit" class="w-[50rpx] h-[36rpx]" /> |
|
||||
<text class="text-[28rpx] text-[#FFDAA8] ml-[10rpx] font-bold max-w-[440rpx] truncate">{{info.member_level_name}}</text> |
|
||||
</view> |
|
||||
<view class="flex items-center justify-center rounded-[30rpx] box-border style-btn w-[120rpx] h-[50rpx]" @click="toLink('/app/pages/member/level')"> |
|
||||
<text class="text-[24rpx] text-[#333]">{{ info.member_level ? (upgradeGrowth > 0 ? '去升级' : '去查看') : '去解锁' }}</text> |
|
||||
<text class="iconfont iconxiayibu1 ml-[2rpx] !text-[20rpx] text-[#333]"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-if="diyComponent.style == 'style-2'" class="rounded-[16rpx] flex items-center justify-between style-bg-2 p-[30rpx]"> |
|
||||
<view class="flex flex-col"> |
|
||||
<view class="flex items-center"> |
|
||||
<image :src="img('static/resource/images/diy/member/VIP_01.png')" mode="aspectFit" class="w-[74rpx] h-[30rpx]" /> |
|
||||
<text class="text-[32rpx] text-[#FFE3B1] leading-[normal] ml-[14rpx] font-bold max-w-[420rpx] truncate">{{info.member_level_name}}</text> |
|
||||
</view> |
|
||||
<text class="text-[#fff] text-[24rpx] mt-[10rpx] leading-[32rpx]" v-if="benefits_arr && benefits_arr.length">{{info.member_level_name}}购物享{{benefits_arr[0].title}}</text> |
|
||||
</view> |
|
||||
<view class="flex items-center justify-center rounded-[30rpx] box-border style-btn w-[120rpx] h-[50rpx]" @click="toLink('/app/pages/member/level')"> |
|
||||
<text class="text-[24rpx] text-[#333]">{{ info.member_level ? (upgradeGrowth > 0 ? '去升级' : '去查看') : '去解锁' }}</text> |
|
||||
<text class="iconfont iconxiayibu1 ml-[2rpx] !text-[20rpx] text-[#333]"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-if="diyComponent.style == 'style-3'" class="rounded-[16rpx] style-bg-3 p-[30rpx]"> |
|
||||
<view class="flex items-center justify-between style-border-3 mb-[22rpx] pb-[22rpx]"> |
|
||||
<view class="flex flex-col"> |
|
||||
<view class="flex items-center"> |
|
||||
<view class="flex justify-end leading-[30rpx] box-border text-[#fff] pr-[10rpx] text-[26rpx] w-[120rpx] h-[30rpx] bg-contain bg-no-repeat" :style="{'backgroundImage': 'url('+img('static/resource/images/diy/member/VIP.png')+')'}"> |
|
||||
VIP.{{currIndex}} |
|
||||
</view> |
|
||||
<text class="text-[#733F02] ml-[8rpx] text-[30rpx] font-bold max-w-[380rpx] truncate">{{info.member_level_name}}</text> |
|
||||
</view> |
|
||||
<text class="text-[28rpx] text-[#794200] mt-[16rpx]">购物或邀请好友可以提升等级</text> |
|
||||
</view> |
|
||||
<view class="flex items-center" @click="toLink('/app/pages/member/level')"> |
|
||||
<view class="flex flex-col items-center justify-center"> |
|
||||
<image :src="img('static/resource/images/diy/member/rule.png')" mode="aspectFit" class="w-[26rpx] h-[26rpx]" /> |
|
||||
<text class="text-[24rpx] text-[#733F02] mt-[10rpx]">规则</text> |
|
||||
</view> |
|
||||
<view class="ml-[10rpx] text-[#733F02] !text-[26rpx] nc-iconfont nc-icon-youV6xx"></view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="flex items-center justify-between"> |
|
||||
<view class="flex flex-col flex-1"> |
|
||||
<view class="overflow-hidden rounded-[20rpx]"> |
|
||||
<progress :percent="progress()" activeColor="#fff" backgroundColor="rgba(255,5,5,.1)" stroke-width="6" /> |
|
||||
</view> |
|
||||
<text class="text-[24rpx] text-[#794200] mt-[16rpx]" v-if="upgradeGrowth > 0">还差{{upgradeGrowth}}成长值即可升级为{{ list[afterCurrIndex].level_name }}</text> |
|
||||
<text class="text-[24rpx] text-[#794200] mt-[16rpx]" v-else>恭喜您升级为最高等级</text> |
|
||||
</view> |
|
||||
<view class="flex items-center rounded-[30rpx] bg-[rgb(245,230,185)] p-[16rpx] ml-[40rpx]" @click="toLink('/app/pages/member/level')"> |
|
||||
<text class="text-[28rpx] text-[#733F02]">{{info.member_level ? (upgradeGrowth > 0 ? '做任务' : '点击查看') : '去解锁'}}</text> |
|
||||
<image :src="img('static/resource/images/diy/member/vector.png')" mode="aspectFit" class="ml-[8rpx] w-[12rpx] h-[18rpx]" /> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { computed, ref, watch } from 'vue' |
|
||||
import { img, redirect } from '@/utils/common' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import { t } from '@/locale' |
|
||||
import { getMemberLevel } from '@/app/api/member'; |
|
||||
import useDiyStore from '@/app/stores/diy' |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
const diyStore = useDiyStore(); |
|
||||
const memberStore = useMemberStore() |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
// 获取会员等级列表 |
|
||||
let list:any = ref([]) |
|
||||
let upgradeGrowth = ref(0) // 升级下级会员所需的成长值 |
|
||||
let currIndex = ref(0) //当前会员索引 |
|
||||
let afterCurrIndex = ref(-1) // 下一个会员等级索引 |
|
||||
let benefits_arr:any = ref([]) //当前会员权益 |
|
||||
|
|
||||
const info:any = computed(() => { |
|
||||
// 装修模式 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
upgradeGrowth.value = 0; |
|
||||
benefits_arr.value = [{'title': '商品包邮'}]; |
|
||||
currIndex.value = 1; |
|
||||
list.value = [{}]; |
|
||||
|
|
||||
return { |
|
||||
member_level_name: '会员等级', |
|
||||
growth: 5 |
|
||||
} |
|
||||
} else { |
|
||||
if (memberStore.info) { |
|
||||
getMemberLevelFn(); |
|
||||
} |
|
||||
return memberStore.info; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const getMemberLevelFn = ()=> { |
|
||||
getMemberLevel().then((res: any) => { |
|
||||
list.value = res.data; |
|
||||
if(!list.value.length) return false; |
|
||||
|
|
||||
let isSet = false; |
|
||||
|
|
||||
// 刚进来处理会员等级数据 |
|
||||
if (info.value && list.value && list.value.length) { |
|
||||
list.value.forEach((item: any, index: any) => { |
|
||||
if (item.level_id == info.value.member_level) { |
|
||||
currIndex.value = index + 1; |
|
||||
// 会员权益 |
|
||||
if (item.level_benefits) { |
|
||||
Object.values(item.level_benefits).forEach((bItem: any) => { |
|
||||
if (bItem.content) { |
|
||||
benefits_arr.value.push(bItem.content) |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (item.growth > info.value.growth && !isSet) { |
|
||||
afterCurrIndex.value = index; |
|
||||
isSet = true; |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
if (info.value.member_level) { |
|
||||
if(afterCurrIndex.value == -1){ |
|
||||
afterCurrIndex.value = list.value.length - 1; |
|
||||
} |
|
||||
|
|
||||
if (list.value[afterCurrIndex.value] && list.value[afterCurrIndex.value].growth) { |
|
||||
upgradeGrowth.value = list.value[afterCurrIndex.value].growth - info.value.growth; |
|
||||
} |
|
||||
}else{ |
|
||||
// 当前会员没有会员等级,则展示会员等级中的最后一个等级 |
|
||||
info.value.member_level_name = list.value[0].level_name; |
|
||||
upgradeGrowth.value = list.value[0].growth; |
|
||||
afterCurrIndex.value = 0; |
|
||||
currIndex.value = 1; |
|
||||
} |
|
||||
|
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// 进度条值 |
|
||||
let progress = () => { |
|
||||
let num = 100 |
|
||||
if(list.value[afterCurrIndex.value] && list.value[afterCurrIndex.value].growth) { |
|
||||
if(info.value.growth) { |
|
||||
num = info.value.growth / list.value[afterCurrIndex.value].growth * 100 |
|
||||
}else{ |
|
||||
num = 0 |
|
||||
} |
|
||||
} |
|
||||
return num |
|
||||
} |
|
||||
|
|
||||
// 跳转链接 |
|
||||
const toLink = (link: string)=>{ |
|
||||
if (diyStore.mode == 'decorate') return false; |
|
||||
redirect({ url: link }) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.style-bg-1{ |
|
||||
background: linear-gradient(to right, #1F1313, #4D4646); |
|
||||
} |
|
||||
.style-btn{ |
|
||||
background: linear-gradient(to right, #FFEACB, #FFD195); |
|
||||
} |
|
||||
.style-bg-2{ |
|
||||
background: linear-gradient(to right, #484846, #222222); |
|
||||
border-bottom-left-radius: 320rpx 16rpx; |
|
||||
border-bottom-right-radius: 320rpx 16rpx; |
|
||||
} |
|
||||
.style-bg-3{ |
|
||||
background: linear-gradient(to right, #FFE6C2, #E39F42); |
|
||||
} |
|
||||
.style-border-3{ |
|
||||
position: relative; |
|
||||
&:after{ |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
background: linear-gradient(to right, #F0D2A9, #DBA051); |
|
||||
height: 2rpx; |
|
||||
bottom: 0; |
|
||||
left: 0; |
|
||||
right: 0; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,291 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view class="diy-notice relative overflow-hidden"> |
|
||||
<view class="flex items-center pl-[28rpx] p-[22rpx]"> |
|
||||
<template v-if="diyComponent.noticeType == 'img'"> |
|
||||
<template v-if="diyComponent.imgType == 'system'"> |
|
||||
<image v-if="diyComponent.systemUrl == 'style_1'" :src="img(`static/resource/images/diy/notice/${diyComponent.systemUrl}.png`)" class="h-[40rpx] max-w-[130rpx] mr-[20rpx] flex-shrink-0" mode="heightFix"/> |
|
||||
<image v-else-if="diyComponent.systemUrl == 'style_2'" :src="img(`static/resource/images/diy/notice/${diyComponent.systemUrl}.png`)" class="w-[200rpx] mr-[20rpx] h-[40rpx] flex-shrink-0" mode="heightFix" /> |
|
||||
</template> |
|
||||
<image v-else-if="diyComponent.imgType == 'diy'" :src="img(diyComponent.imageUrl || '')" class="w-[50rpx] h-[50rpx] mr-[20rpx] flex-shrink-0" mode="heightFix"/> |
|
||||
</template> |
|
||||
<view v-if="diyComponent.noticeType == 'text' && diyComponent.noticeTitle" class="max-w-[128rpx] px-[12rpx] text-[26rpx] h-[40rpx] leading-[40rpx] text-[var(--primary-color)] bg-[var(--primary-color-light)] truncate rounded-[8rpx] mr-[20rpx] flex-shrink-0">{{ diyComponent.noticeTitle }}</view> |
|
||||
<view class="flex-1 flex overflow-hidden horizontal-body" id="horizontal-body" :class="{'items-center':diyComponent.scrollWay == 'upDown'}"> |
|
||||
<!-- 横向滚动 --> |
|
||||
<view class="horizontal-wrap" :style="marqueeStyle" v-if="diyComponent.scrollWay == 'horizontal'"> |
|
||||
<view class="marquee marquee-one" id="marquee-one" > |
|
||||
<view class="item flex-shrink-0 !leading-[40rpx] h-[40rpx]" :class="{'ml-[80rpx]':index}" v-for="(item, index) in diyComponent.list" :key="index" @click="toRedirect(item)" :style="{ color: diyComponent.textColor, fontSize: diyComponent.fontSize * 2 + 'rpx', fontWeight: diyComponent.fontWeight }">{{ item.text }}</view> |
|
||||
</view> |
|
||||
<view class="marquee"> |
|
||||
<view class="item flex-shrink-0 !leading-[40rpx] h-[40rpx]" :class="{'ml-[80rpx]':index}" v-for="(item, index) in diyComponent.list" :key="index" @click="toRedirect(item)" :style="{ color: diyComponent.textColor, fontSize: diyComponent.fontSize * 2 + 'rpx', fontWeight: diyComponent.fontWeight }">{{ item.text }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<!-- 上下滚动 --> |
|
||||
<template v-if="diyComponent.scrollWay == 'upDown'"> |
|
||||
<swiper :vertical="true" :duration="500" autoplay="true" circular="true" class="flex-1"> |
|
||||
<swiper-item v-for="(item, index) in diyComponent.list" :key="index" @touchmove.prevent.stop> |
|
||||
<text @click="toRedirect(item)" class="beyond-hiding using-hidden" :style="{ color: diyComponent.textColor, fontSize: diyComponent.fontSize * 2 + 'rpx', fontWeight: diyComponent.fontWeight }"> |
|
||||
{{ item.text }} |
|
||||
</text> |
|
||||
</swiper-item> |
|
||||
</swiper> |
|
||||
<text class="nc-iconfont nc-icon-youV6xx text-[26rpx] -ml-[8rpx] pl-[30rpx]" :style="{'color': '#999', 'fontWeight': diyComponent.fontWeight}"></text> |
|
||||
|
|
||||
</template> |
|
||||
</view> |
|
||||
|
|
||||
</view> |
|
||||
|
|
||||
<u-popup :show="noticeShow" @close="noticeShow = false" mode="center" :round="5" :safeAreaInsetBottom="false"> |
|
||||
<view @touchmove.prevent.stop> |
|
||||
<view class="py-[25rpx] text-sm leading-none border-0 border-solid border-b-[2rpx] border-[#eee] flex items-center justify-between"> |
|
||||
<text class="ml-[30rpx]">公告</text> |
|
||||
<text class="mr-[20rpx] nc-iconfont nc-icon-guanbiV6xx text-[35rpx]" @click="noticeShow = false"></text> |
|
||||
</view> |
|
||||
<scroll-view scroll-y="true" class="px-6 py-3 w-[480rpx] h-[500rpx] text-sm">{{ noticeContent }}</scroll-view> |
|
||||
<button @click="noticeShow = false" class="!mx-[30rpx] !mb-[40rpx] !w-auto !h-[70rpx] text-[24rpx] leading-[70rpx] rounded-full text-white !bg-[#ff4500] !text-[#fff]">我知道了</button> |
|
||||
</view> |
|
||||
</u-popup> |
|
||||
|
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 公告组件 |
|
||||
import { ref,computed, watch, onMounted, nextTick,getCurrentInstance } from 'vue'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
const diyStore = useDiyStore(); |
|
||||
const noticeShow = ref(false); |
|
||||
const noticeContent = ref(''); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
const marqueeBodyWidth = ref(0); // 容器宽度 |
|
||||
const marqueeStyle = ref(''); // 横向滚动样式 |
|
||||
const time = ref(0); // 滚动完成时间 |
|
||||
const delayTime = ref(800); // 动画延迟时间 |
|
||||
// px转rpx |
|
||||
const pxToRpx=(px)=> { |
|
||||
const screenWidth = uni.getSystemInfoSync().screenWidth |
|
||||
return (750 * Number.parseInt(px)) / screenWidth |
|
||||
} |
|
||||
// 绑定横向滚动事件 |
|
||||
const bindCrossSlipEvent = ()=> { |
|
||||
if (diyComponent.value.scrollWay == 'horizontal') { |
|
||||
setTimeout(() => { |
|
||||
nextTick(() => { |
|
||||
// #ifdef MP-WEIXIN |
|
||||
uni.createSelectorQuery().in(instance).select('.horizontal-body').boundingClientRect(res => { |
|
||||
marqueeBodyWidth.value = res.width; |
|
||||
console.log(pxToRpx(res.width)) |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.selectAll('.marquee-one').boundingClientRect((data:any) => { |
|
||||
let width = data[0].width |
|
||||
time.value = pxToRpx(width) * 10; |
|
||||
if (marqueeBodyWidth.value > width) { |
|
||||
marqueeStyle.value = `animation: none;`; |
|
||||
} else { |
|
||||
marqueeStyle.value = ` |
|
||||
animation-duration: ${time.value}ms; |
|
||||
animation-delay: ${delayTime.value}ms;`; |
|
||||
} |
|
||||
}).exec(); |
|
||||
}).exec(); |
|
||||
// #endif |
|
||||
// #ifdef H5 |
|
||||
marqueeBodyWidth.value = window.document.getElementById('horizontal-body').offsetWidth; |
|
||||
const width = window.document.getElementById('marquee-one').offsetWidth; |
|
||||
time.value = pxToRpx(width) * 10; |
|
||||
if (marqueeBodyWidth.value > width) { |
|
||||
marqueeStyle.value = `animation: none;`; |
|
||||
} else { |
|
||||
marqueeStyle.value = ` |
|
||||
animation-duration: ${time.value}ms; |
|
||||
animation-delay: ${delayTime.value}ms;`; |
|
||||
} |
|
||||
// #endif |
|
||||
}); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
onMounted(() => { |
|
||||
bindCrossSlipEvent(); |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'Notice') { |
|
||||
bindCrossSlipEvent(); |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = ()=> { |
|
||||
nextTick(() => { |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.diy-notice').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const toRedirect = (data: {}) => { |
|
||||
if (diyStore.mode == 'decorate') return false; |
|
||||
|
|
||||
if (diyComponent.value.showType == 'popup') { |
|
||||
noticeShow.value = true; |
|
||||
noticeContent.value = data.text; |
|
||||
} else { |
|
||||
diyStore.toRedirect(data); |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.main-wrap { |
|
||||
display: inline-block; |
|
||||
width: calc(100% - 100rpx); |
|
||||
position: relative; |
|
||||
} |
|
||||
|
|
||||
swiper { |
|
||||
height: 50rpx; |
|
||||
} |
|
||||
|
|
||||
.beyond-hiding { |
|
||||
display: inline-block; |
|
||||
width: 100%; |
|
||||
white-space: nowrap; |
|
||||
line-height: 50rpx |
|
||||
} |
|
||||
|
|
||||
.notice-popup { |
|
||||
padding: 0 30rpx 40rpx; |
|
||||
background-color: #fff; |
|
||||
|
|
||||
.head-wrap { |
|
||||
font-size: 32rpx; |
|
||||
line-height: 100rpx; |
|
||||
height: 100rpx; |
|
||||
display: block; |
|
||||
text-align: center; |
|
||||
position: relative; |
|
||||
border-bottom: 2rpx solid #eeeeee; |
|
||||
margin-bottom: 20rpx; |
|
||||
|
|
||||
.iconfont { |
|
||||
position: absolute; |
|
||||
float: right; |
|
||||
right: 0; |
|
||||
font-size: 32rpx; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.content-wrap { |
|
||||
max-height: 600rpx; |
|
||||
overflow-y: auto; |
|
||||
} |
|
||||
|
|
||||
button { |
|
||||
margin-top: 40rpx; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.horizontal-wrap { |
|
||||
height: 40rpx; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
transform: translateZ(0); |
|
||||
animation: marquee 0s 0s linear infinite; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
.marquee { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
height: 100%; |
|
||||
white-space: nowrap; |
|
||||
padding-right: 60rpx; |
|
||||
// backface-visibility: hidden; |
|
||||
// -webkit-perspective: 1000; |
|
||||
// -moz-perspective: 1000; |
|
||||
// -ms-perspective: 1000; |
|
||||
// perspective: 1000; |
|
||||
} |
|
||||
|
|
||||
@keyframes marquee { |
|
||||
0% { |
|
||||
transform: translateX(0); |
|
||||
} |
|
||||
|
|
||||
100% { |
|
||||
transform: translateX(-50%); |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,125 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view class="diy-rich-text relative"> |
|
||||
<view v-if="diyComponent.html && diyComponent.html != '<p><br></p>'"> |
|
||||
<u-parse :content="diyComponent.html" :tagStyle="{img: 'vertical-align: top;'}"></u-parse> |
|
||||
</view> |
|
||||
<template v-else> |
|
||||
<view>点此编辑『富文本』内容 ——></view> |
|
||||
<view> |
|
||||
<text>你可以对文字进行</text> |
|
||||
<text>、</text> |
|
||||
<text class="font-bold">加粗</text> |
|
||||
<text>、</text> |
|
||||
<text class="italic">斜体</text> |
|
||||
<text>、</text> |
|
||||
<text class="underline">下划线</text> |
|
||||
<text>、</text> |
|
||||
<text class="line-through">删除线</text> |
|
||||
<text>、文字</text> |
|
||||
<text style="color: rgb(0, 176, 240);">颜色</text> |
|
||||
<text>、</text> |
|
||||
<text style="background-color: rgb(255, 192, 0); color: rgb(255, 255, 255);">背景色</text> |
|
||||
<text>、以及字号</text> |
|
||||
<text class="text-lg">大</text> |
|
||||
<text class="text-sm">小</text> |
|
||||
<text class="pl-[10rpx]">等简单排版操作。</text> |
|
||||
</view> |
|
||||
<view>也可在这里插入图片、并对图片加上超级链接,方便用户点击。</view> |
|
||||
</template> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 富文本组件 |
|
||||
import { ref,computed, watch, onMounted, nextTick,getCurrentInstance } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'RichText') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = ()=> { |
|
||||
nextTick(() => { |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.diy-rich-text').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,590 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view :class="['rubik-cube relative', diyStore.mode]"> |
|
||||
|
|
||||
<!-- 1左2右 --> |
|
||||
<template v-if="diyComponent.mode == 'row1-lt-of2-rt'"> |
|
||||
<view class="template-left"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.list[0].link)" :class="['item', diyComponent.mode]" |
|
||||
:style="{ marginRight: diyComponent.imageGap * 2 + 'rpx', width: diyComponent.list[0].imgWidth, height: diyComponent.list[0].imgHeight + 'px' }"> |
|
||||
<image v-if="diyComponent.list[0].imageUrl" :src="img(diyComponent.list[0].imageUrl)" mode="scaleToFill" :style="diyComponent.list[0].pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="scaleToFill" :style="diyComponent.list[0].pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<view class="template-right"> |
|
||||
<template v-for="(item, index) in diyComponent.list" :key="index"> |
|
||||
<template v-if="index > 0"> |
|
||||
<view @click="diyStore.toRedirect(item.link)" :class="['item', diyComponent.mode]" |
|
||||
:style="{ marginBottom: diyComponent.imageGap * 2 + 'rpx', width: item.imgWidth, height: item.imgHeight + 'px' }"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="scaleToFill" :style="item.pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="scaleToFill" :style="item.pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</template> |
|
||||
</template> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 1左3右 --> |
|
||||
<template v-else-if="diyComponent.mode == 'row1-lt-of1-tp-of2-bm'"> |
|
||||
<view class="template-left"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.list[0].link)" :class="['item', diyComponent.mode]" |
|
||||
:style="{ marginRight: diyComponent.imageGap * 2 + 'rpx', width: diyComponent.list[0].imgWidth, height: diyComponent.list[0].imgHeight + 'px' }"> |
|
||||
<image v-if="diyComponent.list[0].imageUrl" :src="img(diyComponent.list[0].imageUrl)" mode="scaleToFill" :style="diyComponent.list[0].pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="scaleToFill" :style="diyComponent.list[0].pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<view class="template-right"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.list[1].link)" :class="['item', diyComponent.mode]" |
|
||||
:style="{ marginBottom: diyComponent.imageGap * 2 + 'rpx', width: diyComponent.list[1].imgWidth, height: diyComponent.list[1].imgHeight + 'px' }"> |
|
||||
<image v-if="diyComponent.list[1].imageUrl" :src="img(diyComponent.list[1].imageUrl)" mode="scaleToFill" :style="diyComponent.list[1].pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="scaleToFill" :style="diyComponent.list[1].pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
<view class="template-bottom"> |
|
||||
<template v-for="(item, index) in diyComponent.list" :key="index"> |
|
||||
<template v-if="index > 1"> |
|
||||
<view @click="diyStore.toRedirect(item.link)" :class="['item', diyComponent.mode]" :style="{ |
|
||||
marginRight: diyComponent.imageGap * 2 + 'rpx', |
|
||||
width: item.imgWidth, |
|
||||
height: item.imgHeight + 'px' |
|
||||
}"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" mode="scaleToFill" :style="item.pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" mode="scaleToFill" :style="item.pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</template> |
|
||||
</template> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<template v-else> |
|
||||
<view :class="['item', diyComponent.mode]" v-for="(item, index) in diyComponent.list" :key="index" |
|
||||
@click="diyStore.toRedirect(item.link)" |
|
||||
:style="{ marginRight: diyComponent.imageGap * 2 + 'rpx', marginBottom: diyComponent.imageGap * 2 + 'rpx', width: item.widthStyle, height: item.imgHeight + 'px' }"> |
|
||||
<image v-if="item.imageUrl" :src="img(item.imageUrl)" :mode="'scaleToFill'" :style="item.pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
<image v-else :src="img('static/resource/images/diy/figure.png')" :mode="'scaleToFill'" :style="item.pageItemStyle" :show-menu-by-longpress="true"/> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 魔方 |
|
||||
import { ref,onMounted, computed, watch,nextTick,getCurrentInstance } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
|
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
/** |
|
||||
* 处理rpx渲染之后变成rem存在小数的问题 |
|
||||
* @param rpx |
|
||||
*/ |
|
||||
const upx2px = (rpx: number) => { |
|
||||
return uni.upx2px(rpx) + 1 |
|
||||
} |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
const countBorderRadius = (type, index) => { |
|
||||
var obj = ''; |
|
||||
if (diyComponent.value.elementAngle == 'right') { |
|
||||
return obj; |
|
||||
} |
|
||||
var defaultData:any = { |
|
||||
'row1-lt-of2-rt': [ |
|
||||
['border-top-right-radius', 'border-bottom-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius', 'border-bottom-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius'] |
|
||||
], |
|
||||
'row1-lt-of1-tp-of2-bm': [ |
|
||||
['border-top-right-radius', 'border-bottom-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius', 'border-bottom-right-radius'], |
|
||||
['border-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius'] |
|
||||
], |
|
||||
'row1-tp-of2-bm': [ |
|
||||
['border-bottom-left-radius', 'border-bottom-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-right-radius', 'border-top-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius'] |
|
||||
], |
|
||||
'row2-lt-of2-rt': [ |
|
||||
['border-top-right-radius', 'border-bottom-left-radius', 'border-bottom-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-right-radius', 'border-bottom-left-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-right-radius', 'border-top-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius'] |
|
||||
], |
|
||||
'row1-of4': [ |
|
||||
['border-top-right-radius', 'border-bottom-right-radius'], |
|
||||
['border-radius'], |
|
||||
['border-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius'] |
|
||||
], |
|
||||
'row1-of3': [ |
|
||||
['border-top-right-radius', 'border-bottom-right-radius'], |
|
||||
['border-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius'] |
|
||||
], |
|
||||
'row1-of2': [ |
|
||||
['border-top-right-radius', 'border-bottom-right-radius'], |
|
||||
['border-top-left-radius', 'border-bottom-left-radius'] |
|
||||
] |
|
||||
}; |
|
||||
|
|
||||
defaultData[type][index].forEach((item, index) => { |
|
||||
obj += 'border-top-left-radius:' + diyComponent.value.topElementRounded * 2 + 'rpx;'; |
|
||||
obj += 'border-top-right-radius:' + diyComponent.value.topElementRounded * 2 + 'rpx;'; |
|
||||
obj += 'border-bottom-left-radius:' + diyComponent.value.bottomElementRounded * 2 + 'rpx;'; |
|
||||
obj += 'border-bottom-right-radius:' + diyComponent.value.bottomElementRounded * 2 + 'rpx;'; |
|
||||
}); |
|
||||
return obj; |
|
||||
} |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'RubikCube') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
}else{ |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
refresh(); |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = () => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
diyComponent.value.list.forEach((item : any) => { |
|
||||
// 装修模式下设置默认图 |
|
||||
if (item.imageUrl == '') { |
|
||||
item.imgWidth = 690; |
|
||||
item.imgHeight = 330; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
handleData() |
|
||||
nextTick(() => { |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.rubik-cube').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const handleData = () => { |
|
||||
var singleRow:any = { |
|
||||
'row1-of2': { |
|
||||
ratio: 2, |
|
||||
width: 'calc((100% - ' + upx2px(diyComponent.value.imageGap * 2) + 'px) / 2)' |
|
||||
}, |
|
||||
'row1-of3': { |
|
||||
ratio: 3, |
|
||||
width: 'calc((100% - ' + upx2px(diyComponent.value.imageGap * 4) + 'px) / 3)' |
|
||||
}, |
|
||||
'row1-of4': { |
|
||||
ratio: 4, |
|
||||
width: 'calc((100% - ' + upx2px(diyComponent.value.imageGap * 6) + 'px) / 4)' |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
item.pageItemStyle = countBorderRadius(diyComponent.value.mode, index); |
|
||||
}); |
|
||||
|
|
||||
if (singleRow[diyComponent.value.mode]) { |
|
||||
calcSingleRow(singleRow[diyComponent.value.mode]); |
|
||||
} else if (diyComponent.value.mode == 'row2-lt-of2-rt') { |
|
||||
calcFourSquare(); |
|
||||
} else if (diyComponent.value.mode == 'row1-lt-of2-rt') { |
|
||||
calcRowOneLeftOfTwoRight(); |
|
||||
} else if (diyComponent.value.mode == 'row1-tp-of2-bm') { |
|
||||
calcRowOneTopOfTwoBottom(); |
|
||||
} else if (diyComponent.value.mode == 'row1-lt-of1-tp-of2-bm') { |
|
||||
calcRowOneLeftOfOneTopOfTwoBottom(); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 魔方:单行多个,平分宽度 |
|
||||
* 公式: |
|
||||
* 宽度:屏幕宽度/2,示例:375/2=187.5 |
|
||||
* 比例:原图高/原图宽,示例:322/690=0.46 |
|
||||
* 高度:宽度*比例,示例:187.5*0.46=86.25 |
|
||||
*/ |
|
||||
const calcSingleRow = (params:any) => { |
|
||||
uni.getSystemInfo({ |
|
||||
success: res => { |
|
||||
let maxHeight = 0; |
|
||||
|
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
var ratio = item.imgHeight / item.imgWidth; |
|
||||
|
|
||||
let width = res.windowWidth - upx2px(diyComponent.value.margin.both * 2); // 减去左右间距 |
|
||||
if (diyComponent.value.imageGap > 0) { |
|
||||
width -= upx2px(params.ratio * diyComponent.value.imageGap * 2); // 减去间隙 |
|
||||
} |
|
||||
item.imgWidth = width / params.ratio; |
|
||||
item.imgHeight = item.imgWidth * ratio; |
|
||||
|
|
||||
if (maxHeight == 0 || maxHeight < item.imgHeight) maxHeight = item.imgHeight; |
|
||||
}) |
|
||||
|
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
item.widthStyle = params.width; |
|
||||
item.imgHeight = maxHeight; |
|
||||
}); |
|
||||
} |
|
||||
}) |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* 魔方:四方型,各占50% |
|
||||
*/ |
|
||||
const calcFourSquare = () => { |
|
||||
uni.getSystemInfo({ |
|
||||
success: res => { |
|
||||
let maxHeightFirst = 0; |
|
||||
let maxHeightTwo = 0; |
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
var ratio = item.imgHeight / item.imgWidth; |
|
||||
item.imgWidth = res.windowWidth; |
|
||||
item.imgWidth -= upx2px(diyComponent.value.margin.both * 4); |
|
||||
if (diyComponent.value.imageGap > 0) { |
|
||||
item.imgWidth -= upx2px(diyComponent.value.imageGap * 2); |
|
||||
} |
|
||||
item.imgWidth = item.imgWidth / 2; |
|
||||
item.imgHeight = item.imgWidth * ratio; |
|
||||
|
|
||||
// 获取每行最大高度 |
|
||||
if (index <= 1) { |
|
||||
if (maxHeightFirst == 0 || maxHeightFirst < item.imgHeight) { |
|
||||
maxHeightFirst = item.imgHeight; |
|
||||
} |
|
||||
} else if (index > 1) { |
|
||||
if (maxHeightTwo == 0 || maxHeightTwo < item.imgHeight) { |
|
||||
maxHeightTwo = item.imgHeight; |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
item.imgWidth = 'calc((100% - ' + upx2px(diyComponent.value.imageGap * 2) + 'px) / 2)'; |
|
||||
item.widthStyle = item.imgWidth; |
|
||||
if (index <= 1) { |
|
||||
item.imgHeight = maxHeightFirst; |
|
||||
} else if (index > 1) { |
|
||||
item.imgHeight = maxHeightTwo; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 魔方:1左2右 |
|
||||
*/ |
|
||||
const calcRowOneLeftOfTwoRight = () => { |
|
||||
let rightHeight = 0; // 右侧两图平分高度 |
|
||||
let divide = 'left'; // 划分规则,left:左,right:右 |
|
||||
if (diyComponent.value.list[1].imgWidth === diyComponent.value.list[2].imgWidth) divide = 'right'; |
|
||||
uni.getSystemInfo({ |
|
||||
success: res => { |
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
if (index == 0) { |
|
||||
var ratio = item.imgHeight / item.imgWidth; // 获取左图的尺寸比例 |
|
||||
item.imgWidth = res.windowWidth - upx2px(diyComponent.value.margin.both * 4) - upx2px(diyComponent.value.imageGap * 2); |
|
||||
item.imgWidth = item.imgWidth / 2; |
|
||||
item.imgHeight = item.imgWidth * ratio; |
|
||||
rightHeight = (item.imgHeight - upx2px(diyComponent.value.imageGap * 2)) / 2; |
|
||||
item.imgWidth += 'px'; |
|
||||
} else { |
|
||||
item.imgWidth = diyComponent.value.list[0].imgWidth; |
|
||||
item.imgHeight = rightHeight; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 魔方:1上2下 |
|
||||
*/ |
|
||||
const calcRowOneTopOfTwoBottom = () => { |
|
||||
var maxHeight = 0; |
|
||||
uni.getSystemInfo({ |
|
||||
success: res => { |
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
|
|
||||
var ratio = item.imgHeight / item.imgWidth; // 获取左图的尺寸比例 |
|
||||
if (index == 0) { |
|
||||
item.imgWidth = res.windowWidth - upx2px(diyComponent.value.margin.both * 4); |
|
||||
} else if (index > 0) { |
|
||||
item.imgWidth = res.windowWidth - upx2px(diyComponent.value.margin.both * 4) - upx2px(diyComponent.value.imageGap * 2); |
|
||||
item.imgWidth = item.imgWidth / 2; |
|
||||
} |
|
||||
|
|
||||
item.imgHeight = item.imgWidth * ratio; |
|
||||
|
|
||||
// 获取最大高度 |
|
||||
if (index > 0 && (maxHeight == 0 || maxHeight < item.imgHeight)) maxHeight = item.imgHeight; |
|
||||
|
|
||||
}); |
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
item.imgWidth += 'px'; |
|
||||
item.widthStyle = item.imgWidth; |
|
||||
if (index > 0) item.imgHeight = maxHeight; |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 魔方:1左3右 |
|
||||
*/ |
|
||||
const calcRowOneLeftOfOneTopOfTwoBottom = () => { |
|
||||
uni.getSystemInfo({ |
|
||||
success: res => { |
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
// 左图 |
|
||||
if (index == 0) { |
|
||||
var ratio = item.imgHeight / item.imgWidth; // 获取左图的尺寸比例 |
|
||||
item.imgWidth = res.windowWidth - upx2px(diyComponent.value.margin.both * 4) - upx2px(diyComponent.value.imageGap * 2); |
|
||||
item.imgWidth = item.imgWidth / 2; |
|
||||
item.imgHeight = item.imgWidth * ratio; |
|
||||
} else if (index == 1) { |
|
||||
item.imgWidth = diyComponent.value.list[0].imgWidth; |
|
||||
item.imgHeight = (diyComponent.value.list[0].imgHeight - upx2px(diyComponent.value.imageGap * 2)) / 2; |
|
||||
} else if (index > 1) { |
|
||||
item.imgWidth = (diyComponent.value.list[0].imgWidth - upx2px(diyComponent.value.imageGap * 2)) / 2; |
|
||||
item.imgHeight = diyComponent.value.list[1].imgHeight; |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
diyComponent.value.list.forEach((item, index) => { |
|
||||
item.imgWidth += 'px'; |
|
||||
}); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
.rubik-cube { |
|
||||
overflow: hidden; |
|
||||
display: flex; |
|
||||
flex-wrap: wrap; |
|
||||
justify-content: space-between; |
|
||||
|
|
||||
.item { |
|
||||
text-align: center; |
|
||||
line-height: 0; |
|
||||
overflow: hidden; |
|
||||
|
|
||||
image { |
|
||||
width: 100%; |
|
||||
max-width: 100%; |
|
||||
height: 100%; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 一行两个 |
|
||||
.rubik-cube .item.row1-of2 { |
|
||||
box-sizing: border-box; |
|
||||
margin-top: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-of2:nth-child(1) { |
|
||||
margin-left: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-of2:nth-child(2) { |
|
||||
margin-right: 0 !important; |
|
||||
} |
|
||||
|
|
||||
// 一行三个 |
|
||||
.rubik-cube .item.row1-of3 { |
|
||||
box-sizing: border-box; |
|
||||
margin-top: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-of3:nth-child(1) { |
|
||||
margin-left: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-of3:nth-child(3) { |
|
||||
margin-right: 0 !important; |
|
||||
} |
|
||||
|
|
||||
// 一行四个 |
|
||||
.rubik-cube .item.row1-of4 { |
|
||||
box-sizing: border-box; |
|
||||
margin-top: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-of4:nth-child(1) { |
|
||||
margin-left: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-of4:nth-child(4) { |
|
||||
margin-right: 0 !important; |
|
||||
} |
|
||||
|
|
||||
// 两左两右 |
|
||||
.rubik-cube .item.row2-lt-of2-rt { |
|
||||
// width: 50%; |
|
||||
display: inline-block; |
|
||||
box-sizing: border-box; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row2-lt-of2-rt:nth-child(1) { |
|
||||
margin-left: 0 !important; |
|
||||
margin-top: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row2-lt-of2-rt:nth-child(2) { |
|
||||
margin-right: 0 !important; |
|
||||
margin-top: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row2-lt-of2-rt:nth-child(3) { |
|
||||
margin-left: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row2-lt-of2-rt:nth-child(4) { |
|
||||
margin-right: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
// 一左两右 |
|
||||
.rubik-cube .template-left, |
|
||||
.rubik-cube .template-right { |
|
||||
// width: 50%; |
|
||||
box-sizing: border-box; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .template-left .item.row1-lt-of2-rt:nth-child(1) { |
|
||||
margin-bottom: 0; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .template-right .item.row1-lt-of2-rt:nth-child(2) { |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube.row1-lt-of2-rt .template-right { |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: space-between; |
|
||||
} |
|
||||
|
|
||||
// 一上两下 |
|
||||
.rubik-cube .item.row1-tp-of2-bm:nth-child(1) { |
|
||||
width: 100%; |
|
||||
box-sizing: border-box; |
|
||||
margin-top: 0 !important; |
|
||||
margin-left: 0 !important; |
|
||||
margin-right: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-tp-of2-bm:nth-child(2) { |
|
||||
// width: 50%; |
|
||||
box-sizing: border-box; |
|
||||
margin-left: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .item.row1-tp-of2-bm:nth-child(3) { |
|
||||
// width: 50%; |
|
||||
box-sizing: border-box; |
|
||||
margin-right: 0 !important; |
|
||||
margin-bottom: 0 !important; |
|
||||
} |
|
||||
|
|
||||
// 一左三右 |
|
||||
.rubik-cube .template-left .item.row1-lt-of1-tp-of2-bm { |
|
||||
width: 100%; |
|
||||
box-sizing: border-box; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .template-bottom { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: space-between; |
|
||||
} |
|
||||
|
|
||||
.rubik-cube .template-bottom .item:nth-child(2) { |
|
||||
margin-right: 0 !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,129 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="warpCss"> |
|
||||
<view :style="maskLayer"></view> |
|
||||
<view class="diy-text relative"> |
|
||||
<view v-if="diyComponent.style == 'style-1'" class=" px-[20rpx]"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.link)"> |
|
||||
<view :style="{ |
|
||||
fontSize: diyComponent.fontSize * 2 + 'rpx', |
|
||||
color: diyComponent.textColor, |
|
||||
fontWeight: diyComponent.fontWeight, |
|
||||
textAlign : diyComponent.textAlign |
|
||||
}"> |
|
||||
{{ diyComponent.text }} |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-if="diyComponent.style == 'style-2'" class=" px-[20rpx] flex items-center"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.link)"> |
|
||||
<view class="max-w-[200rpx] truncate" :style="{ |
|
||||
fontSize: diyComponent.fontSize * 2 + 'rpx', |
|
||||
color: diyComponent.textColor, |
|
||||
fontWeight: diyComponent.fontWeight |
|
||||
}"> |
|
||||
{{ diyComponent.text }} |
|
||||
</view> |
|
||||
</view> |
|
||||
<text class="ml-[16rpx] max-w-[300rpx] truncate" :style="{ color: diyComponent.subTitle.color, fontSize: diyComponent.subTitle.fontSize * 2 + 'rpx', }">{{ diyComponent.subTitle.text }}</text> |
|
||||
<view class="ml-auto text-right " v-if="diyComponent.more.isShow" :style="{ color: diyComponent.more.color }"> |
|
||||
<view @click="diyStore.toRedirect(diyComponent.more.link)" class="flex items-center"> |
|
||||
<text class="max-w-[200rpx] truncate text-[24rpx]">{{ diyComponent.more.text }}</text> |
|
||||
<text class="nc-iconfont nc-icon-youV6xx text-[26rpx]" :style="{ color: diyComponent.more.color }"></text> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
// 标题 |
|
||||
import { ref, computed, watch,onMounted,nextTick,getCurrentInstance } from 'vue'; |
|
||||
import useDiyStore from '@/app/stores/diy'; |
|
||||
import { img } from '@/utils/common'; |
|
||||
|
|
||||
const props = defineProps(['component', 'index', 'pullDownRefreshCount']); |
|
||||
const diyStore = useDiyStore(); |
|
||||
|
|
||||
const diyComponent = computed(() => { |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
return diyStore.value[props.index]; |
|
||||
} else { |
|
||||
return props.component; |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const warpCss = computed(() => { |
|
||||
var style = ''; |
|
||||
style += 'position:relative;'; |
|
||||
if(diyComponent.value.componentStartBgColor) { |
|
||||
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`; |
|
||||
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`; |
|
||||
style += 'background-size: cover;background-repeat: no-repeat;'; |
|
||||
} |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
return style; |
|
||||
}) |
|
||||
|
|
||||
// 背景图加遮罩层 |
|
||||
const maskLayer = computed(()=>{ |
|
||||
var style = ''; |
|
||||
if(diyComponent.value.componentBgUrl) { |
|
||||
style += 'position:absolute;top:0;width:100%;'; |
|
||||
style += `background: rgba(0,0,0,${diyComponent.value.componentBgAlpha / 10});`; |
|
||||
style += `height:${height.value}px;`; |
|
||||
|
|
||||
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-left-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;'; |
|
||||
} |
|
||||
|
|
||||
return style; |
|
||||
}); |
|
||||
|
|
||||
watch( |
|
||||
() => props.pullDownRefreshCount, |
|
||||
(newValue, oldValue) => { |
|
||||
// 处理下拉刷新业务 |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
onMounted(() => { |
|
||||
refresh(); |
|
||||
// 装修模式下刷新 |
|
||||
if (diyStore.mode == 'decorate') { |
|
||||
watch( |
|
||||
() => diyComponent.value, |
|
||||
(newValue, oldValue) => { |
|
||||
if (newValue && newValue.componentName == 'Text') { |
|
||||
refresh(); |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const instance = getCurrentInstance(); |
|
||||
const height = ref(0) |
|
||||
|
|
||||
const refresh = ()=> { |
|
||||
nextTick(() => { |
|
||||
const query = uni.createSelectorQuery().in(instance); |
|
||||
query.select('.diy-text').boundingClientRect((data: any) => { |
|
||||
height.value = data.height; |
|
||||
}).exec(); |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
</style> |
|
||||
@ -1,15 +0,0 @@ |
|||||
<template> |
|
||||
<view> |
|
||||
固定模板示例,我也可以装修 |
|
||||
<!-- 自定义模板渲染 --> |
|
||||
<diy-group :data="props.data" :pullDownRefreshCount="props.pullDownRefreshCount"></diy-group> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { computed, watch } from 'vue'; |
|
||||
import diyGroup from '@/addon/components/diy/group/index.vue' |
|
||||
const props = defineProps(['data', 'pullDownRefreshCount']); |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,37 +0,0 @@ |
|||||
<template> |
|
||||
<view class="tags" :style="{ '--backColor': backColor }"> |
|
||||
{{ text }} |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
interface propInt { |
|
||||
text: string |
|
||||
backColor?: string |
|
||||
} |
|
||||
|
|
||||
withDefaults(defineProps<propInt>(), { |
|
||||
text: '', |
|
||||
backColor: '#4b81fb' |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.tags { |
|
||||
position: relative; |
|
||||
margin: 10rpx 0 20rpx; |
|
||||
padding-left: 26rpx; |
|
||||
font-size: 28rpx; |
|
||||
color: #28211f; |
|
||||
|
|
||||
&::before { |
|
||||
content: ''; |
|
||||
position: absolute; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
width: 8rpx; |
|
||||
height: 100%; |
|
||||
background: var(--back-color) !important; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,6 +0,0 @@ |
|||||
{ |
|
||||
"personalSettings": "Personal settings", |
|
||||
"switchLang": "Switch language", |
|
||||
"version": "Version", |
|
||||
"logout": "Log out" |
|
||||
} |
|
||||
@ -1,5 +0,0 @@ |
|||||
{ |
|
||||
"detail": "文章详情", |
|
||||
"abstract": "摘要", |
|
||||
"loadingText": "正在加载" |
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
{ |
|
||||
"list": "文章列表", |
|
||||
"noData": "~ 暂无数据 ~", |
|
||||
"all": "全部", |
|
||||
"end": "-- 到底了 --", |
|
||||
"searchPlaceholder": "请输入搜索关键词" |
|
||||
} |
|
||||
@ -1,10 +0,0 @@ |
|||||
{ |
|
||||
"bindMobile": "绑定手机号", |
|
||||
"bind": "绑定", |
|
||||
"binding": "绑定中", |
|
||||
"agreeTips": "请阅读并同意", |
|
||||
"pleaceAgree": "请勾选已阅读并同意", |
|
||||
"mobilePlaceholder": "请输入手机号", |
|
||||
"codePlaceholder": "请输入验证码", |
|
||||
"weixinUserAuth": "微信用户一键绑定" |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
{ |
|
||||
"logining": "登录中", |
|
||||
"usernamePlaceholder": "请输入账号", |
|
||||
"passwordPlaceholder": "请输入密码", |
|
||||
"resetpwd": "忘记密码", |
|
||||
"noAccount": "还没有账号", |
|
||||
"toRegister": "去注册", |
|
||||
"and": "和", |
|
||||
"agreeTips": "登录代表您同意", |
|
||||
"isAgreeTips": "请先阅读并同意协议", |
|
||||
"usernameLogin": "密码登录", |
|
||||
"mobileLogin": "验证码登录", |
|
||||
"mobilePlaceholder": "请输入手机号" |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
{ |
|
||||
"registering": "注册中", |
|
||||
"usernamePlaceholder": "请输入账号", |
|
||||
"passwordPlaceholder": "请输入密码", |
|
||||
"confirmPasswordPlaceholder": "请再次确认密码", |
|
||||
"confirmPasswordError": "两次输入的密码不一致", |
|
||||
"resetpwd": "忘记密码", |
|
||||
"haveAccount": "已有账号", |
|
||||
"toLogin": "去登录", |
|
||||
"and": "和", |
|
||||
"registerAgreeTips": "注册代表您同意", |
|
||||
"isAgreeTips": "请先阅读并同意协议", |
|
||||
"usernameRegister": "账号注册", |
|
||||
"mobileRegister": "手机号注册", |
|
||||
"mobilePlaceholder": "请输入手机号" |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
{ |
|
||||
"findPassword": "找回密码", |
|
||||
"passwordPlaceholder": "请输入密码", |
|
||||
"confirmPasswordPlaceholder": "请再次确认密码", |
|
||||
"confirmPasswordError": "两次输入的密码不一致" |
|
||||
} |
|
||||
@ -1,10 +0,0 @@ |
|||||
{ |
|
||||
"developTitle":"开发环境配置", |
|
||||
"baseUrl":"API请求地址", |
|
||||
"imgUrl":"图片服务器地址", |
|
||||
"siteId":"站点ID(VITE_SITE_ID)", |
|
||||
"siteIdPlaceholder": "请输入站点ID", |
|
||||
"pleaseEnterNumber":"请输入数字", |
|
||||
"maximumCannotExceed":"最大不能超过" |
|
||||
|
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
{ |
|
||||
"alipayAccountNo": "支付宝账号", |
|
||||
"addBankCard": "添加银行卡", |
|
||||
"addAlipayAccount": "添加支付宝账号", |
|
||||
"endNumber": "尾号", |
|
||||
"bankCard": "银行卡" |
|
||||
} |
|
||||
@ -1,17 +0,0 @@ |
|||||
{ |
|
||||
"addBankCard": "添加银行卡", |
|
||||
"addBankCardTips": "请添加持卡人本人的银行卡", |
|
||||
"addAlipayAccount": "添加支付宝账号", |
|
||||
"addAlipayAccountTips": "请添加已实名的支付宝账号", |
|
||||
"bankRealname": "持卡人姓名", |
|
||||
"bankRealnamePlaceholder": "请输入持卡人姓名", |
|
||||
"bankName": "银行名称", |
|
||||
"bankNamePlaceholder": "请输入银行名称", |
|
||||
"bankAccountNo": "银行卡号", |
|
||||
"bankAccountNoPlaceholder": "请输入银行卡号", |
|
||||
"alipayRealname": "真实姓名", |
|
||||
"alipayRealnamePlaceholder": "请输入真实姓名", |
|
||||
"alipayAccountNo": "支付宝账号", |
|
||||
"alipayAccountNoPlaceholder": "请输入支付宝账号", |
|
||||
"deleteConfirm": "确定要删除该账号吗?" |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
{ |
|
||||
"address": "快递地址", |
|
||||
"locationAddress": "同城配送地址", |
|
||||
"createAddress": "新建收货地址", |
|
||||
"default": "默认" |
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
{ |
|
||||
"name": "收货人", |
|
||||
"namePlaceholder": "请输入收货人姓名", |
|
||||
"mobile": "手机号码", |
|
||||
"mobilePlaceholder": "请输入手机号码", |
|
||||
"selectArea":"选择地区", |
|
||||
"selectAreaPlaceholder":"请选择地区", |
|
||||
"address": "详细地址", |
|
||||
"addressPlaceholder": "请填写详细地址", |
|
||||
"defaultAddress": "设为默认地址", |
|
||||
"selectAddressPlaceholder":"请选择地址" |
|
||||
} |
|
||||
@ -1,30 +0,0 @@ |
|||||
{ |
|
||||
"cashOutNow": "立即提现", |
|
||||
"balanceDetail": "余额明细", |
|
||||
"cashOutTo": "提现到", |
|
||||
"cashOutTypePlaceholder": "请选择提现方式", |
|
||||
"wechatpay": "微信默认钱包", |
|
||||
"cashOutMoneyTip": "提现金额", |
|
||||
"money": "可提现余额", |
|
||||
"allTx": "全部提现", |
|
||||
"minWithdrawal": "最小提现金额为", |
|
||||
"commissionTo": "手续费为", |
|
||||
"cashOutList": "提现记录", |
|
||||
"cashOutToWechat": "提现至微信", |
|
||||
"cashOutToWechatTips": "提现至微信零钱", |
|
||||
"cashOutToAlipay": "提现至支付宝", |
|
||||
"cashOutToAlipayTips": "请先添加支付宝账号", |
|
||||
"cashOutToBank": "提现至银行卡", |
|
||||
"cashOutToBankTips": "请先添加银行卡", |
|
||||
"alipayAccountNo": "支付宝账号", |
|
||||
"debitCard": "储蓄卡", |
|
||||
"abnormalOperation": "异常操作", |
|
||||
"noAvailableCashOutType": "没有可用的提现方式", |
|
||||
"applyMoneyPlaceholder": "请输入提现金额", |
|
||||
"moneyformatError": "提现金额格式错误", |
|
||||
"applyMoneyExceed": "提现金额超出可提现金额", |
|
||||
"applyMoneyBelow": "提现金额小于最低提现金额", |
|
||||
"replace": "更换", |
|
||||
"isOpenApply": "提现设置未开启", |
|
||||
"toAdd": "添加" |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
{ |
|
||||
"balanceInfo": "我的余额", |
|
||||
"recharge": "充值", |
|
||||
"cashOut":"提现", |
|
||||
"balanceDetail": "余额明细", |
|
||||
"accountBalance":"账户余额 (元)", |
|
||||
"balance":"余额 (元)", |
|
||||
"money":"可提现余额 (元)", |
|
||||
"availableBalance": "可用余额", |
|
||||
"rechargeAmountError": "充值金额错误", |
|
||||
"clickRecharge": "立即充值", |
|
||||
"rechargeAmountPlaceholder": "请输入充值金额", |
|
||||
"yuan":"元", |
|
||||
"rechargeRecord":"充值记录" |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
{ |
|
||||
"applyTime": "申请时间", |
|
||||
"toBeReviewed": "官方正在审核,请耐心等待", |
|
||||
"toBeTransfer": "官方正在转账,请耐心等待", |
|
||||
"transfer": "官方已转账,请及时查收", |
|
||||
"cancelApply": "申请已取消", |
|
||||
"balanceDetail": "余额记录", |
|
||||
"commissionDetail": "佣金记录", |
|
||||
"emptyTip": "暂无提现记录", |
|
||||
"commissemptyTip": "暂无佣金记录" |
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
{ |
|
||||
"statusName": "当前状态", |
|
||||
"cashOutNo": "交易号", |
|
||||
"serviceMoney": "手续费", |
|
||||
"createTime": "申请时间", |
|
||||
"auditTime": "审核时间", |
|
||||
"transferBank": "银行名称", |
|
||||
"transferAccount": "收款账号", |
|
||||
"refuseReason": "拒绝理由", |
|
||||
"transferTypeName": "转账方式名称", |
|
||||
"transferTime": "转账时间" |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
{ |
|
||||
"recharge": "充值", |
|
||||
"cashOut":"提现", |
|
||||
"transferMoney":"提现", |
|
||||
"commissionDetail": "佣金明细", |
|
||||
"accountCommission":"当前佣金(元)", |
|
||||
"commission":"累计佣金(元)", |
|
||||
"money":"提现中佣金(元)", |
|
||||
"availableCommission": "可用佣金", |
|
||||
"rechargeAmountError": "充值金额错误", |
|
||||
"clickRecharge": "立即充值", |
|
||||
"rechargeAmountPlaceholder": "请输入充值金额", |
|
||||
"yuan":"元", |
|
||||
"commissionInfo": "我的佣金" |
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
{ |
|
||||
"balanceDetail": "余额明细", |
|
||||
"commissionDetail": "佣金明细", |
|
||||
"balanceEmptyTip": "暂无余额明细", |
|
||||
"moneyEmptyTip": "暂无提现明细", |
|
||||
"commissionEmptyTip": "暂无佣金明细" |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
{ |
|
||||
"name": "收货人", |
|
||||
"namePlaceholder": "请输入收货人姓名", |
|
||||
"mobile": "手机号码", |
|
||||
"mobilePlaceholder": "请输入手机号码", |
|
||||
"deliveryAddress":"收货地址", |
|
||||
"selectAddress":"选择地址", |
|
||||
"selectAddressPlaceholder":"请选择地址", |
|
||||
"address": "楼号门牌", |
|
||||
"addressPlaceholder": "详细地址如 1单元101", |
|
||||
"addressError": "请填写门牌号", |
|
||||
"defaultAddress": "设为默认地址", |
|
||||
"update": "修改" |
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
{ |
|
||||
"nickname": "昵称", |
|
||||
"sex": "性别", |
|
||||
"mobile": "手机号", |
|
||||
"birthday": "生日", |
|
||||
"unknown": "未知", |
|
||||
"updateHeadimg": "更换头像", |
|
||||
"updateNickname": "修改昵称", |
|
||||
"man": "男", |
|
||||
"woman": "女", |
|
||||
"bindMobile": "绑定手机" |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
{ |
|
||||
"rechargeRecord": "充值记录", |
|
||||
"emptyTip": "暂无充值记录" |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
{ |
|
||||
"orderNo": "订单编号", |
|
||||
"createTime": "创建时间" |
|
||||
} |
|
||||
@ -1,13 +0,0 @@ |
|||||
{ |
|
||||
"recharge": "充值", |
|
||||
"cashOut":"提现", |
|
||||
"balanceDetail": "余额明细", |
|
||||
"accountBalance":"账户余额(元)", |
|
||||
"balance":"余额(元)", |
|
||||
"money":"可提现余额(元)", |
|
||||
"availableBalance": "可用余额", |
|
||||
"rechargeAmountError": "充值金额错误", |
|
||||
"clickRecharge": "立即充值", |
|
||||
"rechargeAmountPlaceholder": "请输入充值金额", |
|
||||
"yuan":"元" |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
{ |
|
||||
"personalSettings": "个人设置", |
|
||||
"switchLang": "切换语言", |
|
||||
"version": "版本号", |
|
||||
"logout": "退出登录" |
|
||||
} |
|
||||
@ -1,25 +0,0 @@ |
|||||
<template> |
|
||||
<view v-if="agreement" class="" style="padding: 30rpx;" :style="themeColor()"> |
|
||||
<u-parse :content="agreement.content" :tagStyle="{img: 'vertical-align: top;'}"></u-parse> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { ref } from 'vue' |
|
||||
import { onLoad } from '@dcloudio/uni-app' |
|
||||
import { getAgreementInfo } from '@/app/api/system' |
|
||||
|
|
||||
const agreement = ref(null) |
|
||||
|
|
||||
onLoad((option)=> { |
|
||||
getAgreementInfo(option.key).then((res: AnyObject) => { |
|
||||
agreement.value = res.data |
|
||||
uni.setNavigationBarTitle({ |
|
||||
title: res.data.title |
|
||||
}) |
|
||||
}) |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
</style> |
|
||||
@ -1,205 +0,0 @@ |
|||||
<template> |
|
||||
<view class="w-screen h-screen flex flex-col" :style="themeColor()"> |
|
||||
<view class="flex-1"> |
|
||||
<!-- #ifdef H5 --> |
|
||||
<view class="" style="height: 100rpx;"></view> |
|
||||
<!-- #endif --> |
|
||||
<view class="" style="margin-bottom: 100rpx;padding-top: 100rpx;"> |
|
||||
<view class="font-bold text-lg">{{ t('bindMobile') }}</view> |
|
||||
</view> |
|
||||
<view class=""> |
|
||||
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef"> |
|
||||
<u-form-item label="" prop="mobile" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
<view style="margin-top: 40rpx;"> |
|
||||
<u-form-item label="" prop="mobile_code" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input"> |
|
||||
<template #suffix> |
|
||||
<sms-code :mobile="formData.mobile" type="bind_mobile" v-model="formData.mobile_key"></sms-code> |
|
||||
</template> |
|
||||
</u-input> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view class="flex items-start" style="margin-top: 30rpx;" v-if="!info && config.agreement_show"> |
|
||||
<u-checkbox-group> |
|
||||
<u-checkbox activeColor="var(--primary-color)" :checked="isAgree" shape="shape" size="14" @change="agreeChange" :customStyle="{'marginTop': '4rpx'}" /> |
|
||||
</u-checkbox-group> |
|
||||
<view class="text-xs text-gray-400 flex flex-wrap"> |
|
||||
{{ t('agreeTips') }} |
|
||||
<view @click="redirect({ url: '/app/pages/auth/agreement?key=service' })"> |
|
||||
<text class="text-primary">《{{ t('userAgreement') }}》</text> |
|
||||
</view> |
|
||||
<view @click="redirect({ url: '/app/pages/auth/agreement?key=privacy' })"> |
|
||||
<text class="text-primary">《{{ t('privacyAgreement') }}》</text> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="" style="margin-top: 60rpx;"> |
|
||||
<u-button type="primary" :text="t('bind')" :loading="loading" :loadingText="t('binding')" @click="handleBind"></u-button> |
|
||||
</view> |
|
||||
<!-- #ifdef MP-WEIXIN --> |
|
||||
<view class="" style="margin-top: 30rpx;"> |
|
||||
<u-button type="primary" :plain="true" :text="t('weixinUserAuth')" @click="agreeTips" v-if="!info && config.agreement_show && !isAgree"></u-button> |
|
||||
<u-button type="primary" :plain="true" :text="t('weixinUserAuth')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" v-else></u-button> |
|
||||
</view> |
|
||||
<!-- #endif --> |
|
||||
</u-form> |
|
||||
</view> |
|
||||
</view> |
|
||||
|
|
||||
<!-- #ifdef MP-WEIXIN --> |
|
||||
<!-- 小程序隐私协议 --> |
|
||||
<wx-privacy-popup ref="wxPrivacyPopup"></wx-privacy-popup> |
|
||||
<!-- #endif --> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, computed, onMounted } from 'vue' |
|
||||
import { t } from '@/locale' |
|
||||
import { bind } from '@/app/api/auth' |
|
||||
import { bindMobile } from '@/app/api/member' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import useConfigStore from '@/stores/config' |
|
||||
import { useLogin } from '@/hooks/useLogin' |
|
||||
import { redirect } from '@/utils/common' |
|
||||
|
|
||||
const memberStore = useMemberStore() |
|
||||
const info = computed(() => memberStore.info) |
|
||||
|
|
||||
const config = computed(() => { |
|
||||
return useConfigStore().login |
|
||||
}) |
|
||||
|
|
||||
const loading = ref(false) |
|
||||
const isAgree = ref(false) |
|
||||
|
|
||||
const formData = reactive({ |
|
||||
mobile: '', |
|
||||
mobile_code: '', |
|
||||
mobile_key: '' |
|
||||
}) |
|
||||
|
|
||||
let real_name_input = ref(true); |
|
||||
onMounted(() => { |
|
||||
// 防止浏览器自动填充 |
|
||||
setTimeout(()=>{ |
|
||||
real_name_input.value = false; |
|
||||
},800) |
|
||||
}); |
|
||||
|
|
||||
uni.getStorageSync('openid') && (Object.assign(formData, { openid: uni.getStorageSync('openid') })) |
|
||||
uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') })) |
|
||||
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') })) |
|
||||
|
|
||||
const rules = { |
|
||||
'mobile': [ |
|
||||
{ |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('mobilePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
{ |
|
||||
validator(rule, value, callback) { |
|
||||
let mobile = /^1[3-9]\d{9}$/; |
|
||||
if (!mobile.test(value)){ |
|
||||
callback(new Error('请输入正确的手机号')) |
|
||||
} else { |
|
||||
callback() |
|
||||
} |
|
||||
}, |
|
||||
message: t('mobileError'), |
|
||||
trigger: ['change', 'blur'], |
|
||||
} |
|
||||
], |
|
||||
'mobile_code': { |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('codePlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const agreeChange = () => { |
|
||||
isAgree.value = !isAgree.value |
|
||||
} |
|
||||
|
|
||||
const agreeTips = () => { |
|
||||
uni.showToast({ title: `${t('pleaceAgree')}《${t('userAgreement')}》《${t('privacyAgreement')}》`, icon: 'none' }) |
|
||||
} |
|
||||
|
|
||||
const formRef = ref(null) |
|
||||
|
|
||||
const handleBind = () => { |
|
||||
formRef.value.validate().then(() => { |
|
||||
if (loading.value) return |
|
||||
loading.value = true |
|
||||
|
|
||||
const request = info.value ? bindMobile : bind |
|
||||
|
|
||||
request(formData).then((res) => { |
|
||||
if (info.value) { |
|
||||
memberStore.getMemberInfo() |
|
||||
redirect({ url: '/app/pages/member/personal', mode: 'redirectTo' }) |
|
||||
} else { |
|
||||
memberStore.setToken(res.data.token) |
|
||||
useLogin().handleLoginBack() |
|
||||
} |
|
||||
}).catch(() => { |
|
||||
loading.value = false |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const mobileAuth = (e) => { |
|
||||
if (!isAgree.value && !info.value && config.value.agreement_show) { |
|
||||
uni.showToast({ |
|
||||
title: `${ t('pleaceAgree') }《${ t('userAgreement') }》《${ t('privacyAgreement') }》`, |
|
||||
icon: 'none' |
|
||||
}) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
if (e.detail.errMsg == 'getPhoneNumber:ok') { |
|
||||
uni.showLoading({ title: '' }) |
|
||||
|
|
||||
const request = info.value ? bindMobile : bind |
|
||||
|
|
||||
request({ |
|
||||
openid: formData.openid, |
|
||||
mobile_code: e.detail.code |
|
||||
}).then((res) => { |
|
||||
uni.hideLoading() |
|
||||
if (info.value) { |
|
||||
memberStore.getMemberInfo() |
|
||||
redirect({ url: '/app/pages/member/personal', mode: 'redirectTo' }) |
|
||||
} else { |
|
||||
memberStore.setToken(res.data.token) |
|
||||
useLogin().handleLoginBack() |
|
||||
} |
|
||||
}).catch((res) => { |
|
||||
setTimeout(() => { |
|
||||
uni.hideLoading() |
|
||||
}, 2000); |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
if (e.detail.errno == 104) { |
|
||||
let msg = '用户未授权隐私权限'; |
|
||||
uni.showToast({ title: msg, icon: 'none' }) |
|
||||
} |
|
||||
if (e.detail.errMsg == "getPhoneNumber:fail user deny") { |
|
||||
let msg = '用户拒绝获取手机号码'; |
|
||||
uni.showToast({ title: msg, icon: 'none' }) |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
.u-input{ |
|
||||
background-color: transparent !important; |
|
||||
} |
|
||||
</style> |
|
||||
|
|
||||
@ -1,184 +0,0 @@ |
|||||
<template> |
|
||||
<view class="w-screen h-screen flex flex-col" :style="themeColor()"> |
|
||||
<view class="flex-1"> |
|
||||
<!-- #ifdef H5 --> |
|
||||
<view style="height: 100rpx;"></view> |
|
||||
<!-- #endif --> |
|
||||
<view class="" style="padding-top: 100rpx;margin-bottom: 100rpx;"> |
|
||||
<view class="font-bold text-xl">{{ t('login') }}</view> |
|
||||
</view> |
|
||||
<view class=" text-sm flex font-bold leading-none" style="" v-if="loginType.length > 1"> |
|
||||
<block v-for="(item, index) in loginType"> |
|
||||
<view :class="{'text-gray-300' : item.type != type}" @click="type = item.type">{{ item.title }}</view> |
|
||||
<view class=" border-solid border-gray-300" style="border-radius: 2px;max-width: 30rpx;" v-show="index == 0"></view> |
|
||||
</block> |
|
||||
</view> |
|
||||
<view class=""> |
|
||||
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef"> |
|
||||
<view v-show="type == 'username'"> |
|
||||
<u-form-item label="" prop="username" :border-bottom="true"> |
|
||||
<u-input v-model="formData.username" border="none" clearable :placeholder="t('usernamePlaceholder')" autocomplete="off" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
<view class="" style="margin-top: 40rpx;"> |
|
||||
<u-form-item label="" prop="password" :border-bottom="true"> |
|
||||
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" autocomplete="new-password" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-show="type == 'mobile'"> |
|
||||
<u-form-item label="" prop="mobile" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" autocomplete="off" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
<view class="" style="margin-top: 40rpx;"> |
|
||||
<u-form-item label="" prop="mobile_code" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile_code" border="none" clearable class="!bg-transparent" :disabled="real_name_input" :placeholder="t('codePlaceholder')"> |
|
||||
<template #suffix> |
|
||||
<sms-code :mobile="formData.mobile" type="login" v-model="formData.mobile_key"></sms-code> |
|
||||
</template> |
|
||||
</u-input> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="flex text-xs justify-between text-gray-400" style="margin-top: 40rpx;"> |
|
||||
<view @click="redirect({ url: '/app/pages/auth/register' })">{{ t('noAccount') }} |
|
||||
<text class="text-primary">{{ t('toRegister') }}</text> |
|
||||
</view> |
|
||||
<view @click="redirect({ url: '/app/pages/auth/resetpwd' })">{{ t('resetpwd') }}</view> |
|
||||
</view> |
|
||||
<view class="" style="margin-top: 80rpx;"> |
|
||||
<u-button type="primary" :text="t('login')" :loading="loading" :loadingText="t('logining')" @click="handleLogin"> |
|
||||
</u-button> |
|
||||
</view> |
|
||||
</u-form> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="text-xs flex justify-center w-full" style="" v-if="configStore.login.agreement_show"> |
|
||||
<text class="iconfont " style="font-size: 34rpx;margin-right: 12rpx;" :class="isAgree ? 'iconxuanze1' : 'nc-iconfont nc-icon-yuanquanV6xx'" @click="isAgree = !isAgree"></text> |
|
||||
{{ t('agreeTips') }} |
|
||||
<view @click="redirect({ url: '/app/pages/auth/agreement?key=service' })"> |
|
||||
<text class="text-primary">{{ t('userAgreement') }}</text> |
|
||||
</view> |
|
||||
{{ t('and') }} |
|
||||
<view @click="redirect({ url: '/app/pages/auth/agreement?key=privacy' })"> |
|
||||
<text class="text-primary">{{ t('privacyAgreement') }}</text> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, computed, onMounted } from 'vue' |
|
||||
import { usernameLogin, mobileLogin } from '@/app/api/auth' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import useConfigStore from '@/stores/config' |
|
||||
import { useLogin } from '@/hooks/useLogin' |
|
||||
import { t } from '@/locale' |
|
||||
import { redirect } from '@/utils/common' |
|
||||
|
|
||||
const formData = reactive({ |
|
||||
username: '', |
|
||||
password: '', |
|
||||
mobile: '', |
|
||||
mobile_code: '', |
|
||||
mobile_key: '' |
|
||||
}) |
|
||||
|
|
||||
let real_name_input = ref(true); |
|
||||
onMounted(() => { |
|
||||
// 防止浏览器自动填充 |
|
||||
setTimeout(()=>{ |
|
||||
real_name_input.value = false; |
|
||||
},800) |
|
||||
}); |
|
||||
|
|
||||
if (!uni.getStorageSync('autoLoginLock')) { |
|
||||
uni.getStorageSync('openid') && (Object.assign(formData, { openid: uni.getStorageSync('openid') })) |
|
||||
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') })) |
|
||||
} |
|
||||
uni.getStorageSync('pid') && (Object.assign(formData, { pid: uni.getStorageSync('pid') })) |
|
||||
|
|
||||
const memberStore = useMemberStore() |
|
||||
const configStore = useConfigStore() |
|
||||
|
|
||||
const loading = ref(false) |
|
||||
|
|
||||
const type = ref('') |
|
||||
|
|
||||
const loginType = computed(() => { |
|
||||
const value = [] |
|
||||
configStore.login.is_username && (value.push({ type: 'username', title: t('usernameLogin') })) |
|
||||
configStore.login.is_mobile && (value.push({ type: 'mobile', title: t('mobileLogin') })) |
|
||||
type.value = value[0] ? value[0].type : '' |
|
||||
return value |
|
||||
}) |
|
||||
|
|
||||
const rules = computed(() => { |
|
||||
return { |
|
||||
'username': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'username', |
|
||||
message: t('usernamePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
'password': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'username', |
|
||||
message: t('passwordPlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
}, |
|
||||
'mobile': [ |
|
||||
{ |
|
||||
type: 'string', |
|
||||
required: type.value == 'mobile', |
|
||||
message: t('mobilePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
{ |
|
||||
validator(rule, value) { |
|
||||
if (type.value != 'mobile') return true |
|
||||
else return uni.$u.test.mobile(value) |
|
||||
}, |
|
||||
message: t('mobileError'), |
|
||||
trigger: ['change', 'blur'], |
|
||||
} |
|
||||
], |
|
||||
'mobile_code': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'mobile', |
|
||||
message: t('codePlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const isAgree = ref(false) |
|
||||
|
|
||||
const formRef = ref(null) |
|
||||
|
|
||||
const handleLogin = () => { |
|
||||
formRef.value.validate().then(() => { |
|
||||
if (configStore.login.agreement_show && !isAgree.value) { |
|
||||
uni.showToast({ title: t('isAgreeTips'), icon: 'none' }); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
if (loading.value) return |
|
||||
loading.value = true |
|
||||
|
|
||||
const login = type.value == 'username' ? usernameLogin : mobileLogin |
|
||||
|
|
||||
login(formData).then((res) => { |
|
||||
memberStore.setToken(res.data.token) |
|
||||
useLogin().handleLoginBack() |
|
||||
}).catch(() => { |
|
||||
loading.value = false |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
.u-input{ |
|
||||
background-color: transparent !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,229 +0,0 @@ |
|||||
<template> |
|
||||
<view class="w-screen h-screen flex flex-col" :style="themeColor()"> |
|
||||
<view class="flex-1"> |
|
||||
<!-- #ifdef H5 --> |
|
||||
<view class="" style="height: 100rpx;"></view> |
|
||||
<!-- #endif --> |
|
||||
<view class="" style="padding-top: 100rpx;margin-bottom: 100rpx;"> |
|
||||
<view class="font-bold text-xl">{{ t('register') }}</view> |
|
||||
</view> |
|
||||
<view class=" text-sm flex font-bold leading-none" style="margin-bottom: 50rpx;" v-if="registerType.length > 1"> |
|
||||
<block v-for="(item, index) in registerType"> |
|
||||
<view :class="{'text-gray-300' : item.type != type}" @click="type = item.type">{{ item.title }}</view> |
|
||||
<view class=" border-solid border-0 border-gray-300" style="border-radius: 2px;" v-show="index == 0"></view> |
|
||||
</block> |
|
||||
</view> |
|
||||
<view class=""> |
|
||||
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef"> |
|
||||
<view v-show="type == 'username'"> |
|
||||
<view class="" style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="username" :border-bottom="true"> |
|
||||
<u-input v-model="formData.username" border="none" clearable :placeholder="t('usernamePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="password" :border-bottom="true"> |
|
||||
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="confirm_password" :border-bottom="true"> |
|
||||
<u-input v-model="formData.confirm_password" border="none" type="password" clearable :placeholder="t('confirmPasswordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-show="type == 'mobile' || configStore.login.is_bind_mobile"> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="mobile" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="code" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input"> |
|
||||
<template #suffix> |
|
||||
<sms-code :mobile="formData.mobile" type="register" v-model="formData.mobile_key"></sms-code> |
|
||||
</template> |
|
||||
</u-input> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view v-show="type == 'username'"> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="captcha_code" :border-bottom="true"> |
|
||||
<u-input v-model="formData.captcha_code" border="none" clearable :placeholder="t('captchaPlaceholder')" class="!bg-transparent" :disabled="real_name_input"> |
|
||||
<template #suffix> |
|
||||
<image :src="captcha.image.value" class="" style="height: 48rpx;margin-left: 20rpx;" mode="heightFix" @click="captcha.refresh()"></image> |
|
||||
</template> |
|
||||
</u-input> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="flex text-xs justify-between text-gray-400" style="margin-top: 20rpx;"> |
|
||||
<view @click="redirect({ url: '/app/pages/auth/login' })">{{ t('haveAccount') }},<text class="text-primary">{{ t('toLogin') }}</text></view> |
|
||||
</view> |
|
||||
<view class="" style="margin-top: 80rpx;"> |
|
||||
<u-button type="primary" :text="t('register')" :loading="loading" :loadingText="t('registering')" @click="handleRegister"> |
|
||||
</u-button> |
|
||||
</view> |
|
||||
</u-form> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="text-xs flex justify-center w-full" style="" v-if="configStore.login.agreement_show"> |
|
||||
<text class="iconfont" style="font-style: 34rpx;margin-right: 12rpx;" :class="isAgree ? 'iconxuanze1' : 'nc-iconfont nc-icon-yuanquanV6xx'" @click="isAgree = !isAgree"></text> |
|
||||
{{ t('registerAgreeTips') }} |
|
||||
<view @click="redirect({ url: '/app/pages/auth/agreement?key=service' })"> |
|
||||
<text class="text-primary">{{ t('userAgreement') }}</text> |
|
||||
</view> |
|
||||
{{ t('and') }} |
|
||||
<view @click="redirect({ url: '/app/pages/auth/agreement?key=privacy' })"> |
|
||||
<text class="text-primary">{{ t('privacyAgreement') }}</text> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, computed, onMounted } from 'vue' |
|
||||
import { usernameRegister, mobileRegister } from '@/app/api/auth' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import useConfigStore from '@/stores/config' |
|
||||
import { useLogin } from '@/hooks/useLogin' |
|
||||
import { useCaptcha } from '@/hooks/useCaptcha' |
|
||||
import { t } from '@/locale' |
|
||||
import { redirect } from '@/utils/common' |
|
||||
|
|
||||
const formData = reactive({ |
|
||||
username: '', |
|
||||
password: '', |
|
||||
confirm_password: '', |
|
||||
mobile: '', |
|
||||
mobile_code: '', |
|
||||
mobile_key: '', |
|
||||
captcha_key: '', |
|
||||
captcha_code: '' |
|
||||
}) |
|
||||
|
|
||||
let real_name_input = ref(true); |
|
||||
onMounted(() => { |
|
||||
// 防止浏览器自动填充 |
|
||||
setTimeout(()=>{ |
|
||||
real_name_input.value = false; |
|
||||
},800) |
|
||||
}); |
|
||||
|
|
||||
if (!uni.getStorageSync('autoLoginLock')) { |
|
||||
uni.getStorageSync('openid') && (Object.assign(formData, {openid: uni.getStorageSync('openid')})) |
|
||||
uni.getStorageSync('pid') && (Object.assign(formData, {pid: uni.getStorageSync('pid')})) |
|
||||
} |
|
||||
uni.getStorageSync('unionid') && (Object.assign(formData, { unionid: uni.getStorageSync('unionid') })) |
|
||||
|
|
||||
const captcha = useCaptcha(formData) |
|
||||
captcha.refresh() |
|
||||
|
|
||||
const memberStore = useMemberStore() |
|
||||
const configStore = useConfigStore() |
|
||||
|
|
||||
const loading = ref(false) |
|
||||
|
|
||||
const type = ref('') |
|
||||
|
|
||||
const registerType = computed(()=> { |
|
||||
const value = [] |
|
||||
configStore.login.is_username && (value.push({ type: 'username', title: t('usernameRegister') })) |
|
||||
configStore.login.is_mobile && !configStore.login.is_bind_mobile && (value.push({ type: 'mobile', title: t('mobileRegister') })) |
|
||||
type.value = value[0] ? value[0].type : '' |
|
||||
return value |
|
||||
}) |
|
||||
|
|
||||
const rules = computed(()=>{ |
|
||||
return { |
|
||||
'username': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'username', |
|
||||
message: t('usernamePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
'password': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'username', |
|
||||
message: t('passwordPlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
}, |
|
||||
'confirm_password': [ |
|
||||
{ |
|
||||
type: 'string', |
|
||||
required: type.value == 'username', |
|
||||
message: t('confirmPasswordPlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
}, |
|
||||
{ |
|
||||
validator(rule, value){ |
|
||||
return value == formData.password |
|
||||
}, |
|
||||
message: t('confirmPasswordError'), |
|
||||
trigger: ['change','blur'], |
|
||||
} |
|
||||
], |
|
||||
'mobile': [ |
|
||||
{ |
|
||||
type: 'string', |
|
||||
required: type.value == 'mobile' || configStore.login.is_bind_mobile, |
|
||||
message: t('mobilePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
{ |
|
||||
validator(rule, value){ |
|
||||
if (type.value != 'mobile' && !configStore.login.is_bind_mobile) return true |
|
||||
else return uni.$u.test.mobile(value) |
|
||||
}, |
|
||||
message: t('mobileError'), |
|
||||
trigger: ['change','blur'], |
|
||||
} |
|
||||
], |
|
||||
'mobile_code': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'mobile' || configStore.login.is_bind_mobile, |
|
||||
message: t('codePlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
}, |
|
||||
'captcha_code': { |
|
||||
type: 'string', |
|
||||
required: type.value == 'username', |
|
||||
message: t('captchaPlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const isAgree = ref(false) |
|
||||
|
|
||||
const formRef = ref(null) |
|
||||
|
|
||||
const handleRegister = () => { |
|
||||
formRef.value.validate().then(() => { |
|
||||
if (configStore.login.agreement_show && !isAgree.value) { |
|
||||
uni.showToast({ title: t('isAgreeTips'), icon: 'none' }); |
|
||||
return false; |
|
||||
} |
|
||||
if (loading.value) return |
|
||||
loading.value = true |
|
||||
|
|
||||
const register = type.value == 'username' ? usernameRegister : mobileRegister |
|
||||
|
|
||||
register(formData).then((res: responseResult) => { |
|
||||
memberStore.setToken(res.data.token) |
|
||||
useLogin().handleLoginBack() |
|
||||
}).catch(() => { |
|
||||
loading.value = false |
|
||||
captcha.refresh() |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
.u-input{ |
|
||||
background-color: transparent !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,135 +0,0 @@ |
|||||
<template> |
|
||||
<view class="w-screen h-screen flex flex-col" :style="themeColor()"> |
|
||||
<view class="flex-1"> |
|
||||
<!-- #ifdef H5 --> |
|
||||
<view class="" style="100rpx"></view> |
|
||||
<!-- #endif --> |
|
||||
<view class="" style="padding-top: 100rpx;margin-bottom: 100rpx;"> |
|
||||
<view class="font-bold text-xl">{{ t('findPassword') }}</view> |
|
||||
</view> |
|
||||
|
|
||||
<view class=""> |
|
||||
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef"> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="mobile" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="code" :border-bottom="true"> |
|
||||
<u-input v-model="formData.mobile_code" border="none" clearable :placeholder="t('codePlaceholder')" class="!bg-transparent" :disabled="real_name_input"> |
|
||||
<template #suffix> |
|
||||
<sms-code :mobile="formData.mobile" type="find_pass" v-model="formData.mobile_key"></sms-code> |
|
||||
</template> |
|
||||
</u-input> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="password" :border-bottom="true"> |
|
||||
<u-input v-model="formData.password" border="none" type="password" clearable :placeholder="t('passwordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view style="margin-top: 30rpx;"> |
|
||||
<u-form-item label="" prop="confirm_password" :border-bottom="true"> |
|
||||
<u-input v-model="formData.confirm_password" border="none" type="password" clearable :placeholder="t('confirmPasswordPlaceholder')" class="!bg-transparent" :disabled="real_name_input"/> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
<view class="" style="margin-top: 80rpx;"> |
|
||||
<u-button type="primary" :text="t('confirm')" :loading="loading" :loadingText="t('confirm')" @click="handleConfirm"> |
|
||||
</u-button> |
|
||||
</view> |
|
||||
</u-form> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, onMounted } from 'vue' |
|
||||
import { t } from '@/locale' |
|
||||
import { resetPassword } from '@/app/api/system' |
|
||||
import { redirect } from '@/utils/common' |
|
||||
|
|
||||
const formData = reactive({ |
|
||||
mobile: '', |
|
||||
mobile_code: '', |
|
||||
mobile_key: '', |
|
||||
password: '', |
|
||||
confirm_password: '' |
|
||||
}) |
|
||||
|
|
||||
let real_name_input = ref(true); |
|
||||
onMounted(() => { |
|
||||
// 防止浏览器自动填充 |
|
||||
setTimeout(()=>{ |
|
||||
real_name_input.value = false; |
|
||||
},800) |
|
||||
}); |
|
||||
|
|
||||
const loading = ref(false) |
|
||||
const formRef = ref(null) |
|
||||
|
|
||||
const rules = { |
|
||||
'password': { |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('passwordPlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
}, |
|
||||
'confirm_password': [ |
|
||||
{ |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('confirmPasswordPlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
}, |
|
||||
{ |
|
||||
validator(rule, value) { |
|
||||
return value == formData.password |
|
||||
}, |
|
||||
message: t('confirmPasswordError'), |
|
||||
trigger: ['change', 'blur'], |
|
||||
} |
|
||||
], |
|
||||
'mobile': [ |
|
||||
{ |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('mobilePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
{ |
|
||||
validator(rule, value) { |
|
||||
return uni.$u.test.mobile(value) |
|
||||
}, |
|
||||
message: t('mobileError'), |
|
||||
trigger: ['change', 'blur'], |
|
||||
} |
|
||||
], |
|
||||
'mobile_code': { |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('codePlaceholder'), |
|
||||
trigger: ['blur', 'change'] |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const handleConfirm = () => { |
|
||||
formRef.value.validate().then(() => { |
|
||||
if (loading.value) return |
|
||||
loading.value = true |
|
||||
|
|
||||
resetPassword(formData).then((res : responseResult) => { |
|
||||
redirect({ url: '/app/pages/auth/login', mode: 'redirectTo' }) |
|
||||
}).catch(() => { |
|
||||
loading.value = false |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss"> |
|
||||
.u-input{ |
|
||||
background-color: transparent !important; |
|
||||
} |
|
||||
</style> |
|
||||
|
Before Width: | Height: | Size: 355 B |
@ -1,156 +0,0 @@ |
|||||
<script setup> |
|
||||
import { onLoad } from '@dcloudio/uni-app'; |
|
||||
import { computed, ref } from 'vue'; |
|
||||
import { getProductDetails, orderCalculation, orderCreation } from '@/app/api/home'; |
|
||||
|
|
||||
const imgUrl = import.meta.env.VITE_IMG_DOMAIN; |
|
||||
|
|
||||
const details = ref({}); |
|
||||
const id = ref() |
|
||||
|
|
||||
const getDetails = async () => { |
|
||||
const res = await getProductDetails({ goods_id: id.value }); |
|
||||
console.log(res); |
|
||||
details.value = res.data; |
|
||||
uni.setNavigationBarTitle({ |
|
||||
title: details.value.goods.goods_name |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
const buy = async () => { |
|
||||
// 第一步:计算 |
|
||||
const res = await orderCalculation({ |
|
||||
sku_data: [ { |
|
||||
sku_id: details.value.sku_id, |
|
||||
num: 1 |
|
||||
} ] |
|
||||
}); |
|
||||
if (!res) { |
|
||||
return uni.showToast({ |
|
||||
title: '购买失败' |
|
||||
}); |
|
||||
} |
|
||||
console.log(res); |
|
||||
|
|
||||
|
|
||||
const res2 = await orderCreation({ |
|
||||
order_key: res.data.order_key, |
|
||||
member_remark: '' |
|
||||
}); |
|
||||
|
|
||||
if (!res2) { |
|
||||
return uni.showToast({ |
|
||||
title: '购买失败' |
|
||||
}); |
|
||||
} |
|
||||
uni.navigateTo({ |
|
||||
url: '../../../addon/mine/orderList/orderList?barName=服务订单&is_shop=1', |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
onLoad(async (o) => { |
|
||||
id.value = o.id |
|
||||
uni.showLoading() |
|
||||
await getDetails();+ |
|
||||
uni.hideLoading() |
|
||||
}); |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<div class="commodity"> |
|
||||
<img :src="imgUrl + 'addon/system/backage_3.png'" class="commodity-cover" alt=""/> |
|
||||
<image mode="aspectFill" :src="details.goods.goods_cover" class="commodity-cover" alt=""/> |
|
||||
<div class="commodity-card"> |
|
||||
<p class="commodity-card-title">{{ details.goods.goods_name }}</p> |
|
||||
<p class="commodity-card-description" v-html="details.goods.goods_desc"></p> |
|
||||
</div> |
|
||||
<div class="commodity-footer"> |
|
||||
<div class="commodity-footer-price"> |
|
||||
<div class="commodity-footer-price-iconContainer"> |
|
||||
<img class="commodity-footer-price-iconContainer-img" src="./commodity.png" alt=""/> |
|
||||
</div> |
|
||||
¥{{ details.price }} |
|
||||
</div> |
|
||||
<up-button @click="buy" style="display: inline-flex" shape="circle" color="#4B81FB" |
|
||||
text="立即购买"></up-button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<style scoped lang="scss"> |
|
||||
|
|
||||
.commodity { |
|
||||
width: 100%; |
|
||||
height: 100vh; |
|
||||
position: relative; |
|
||||
background: #F5F8F7; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: space-between; |
|
||||
|
|
||||
&-cover { |
|
||||
width: 100%; |
|
||||
height: 30vh; |
|
||||
object-fit: contain; |
|
||||
} |
|
||||
|
|
||||
&-card { |
|
||||
width: 90%; |
|
||||
height: 60vh; |
|
||||
background: white; |
|
||||
border-radius: 10px; |
|
||||
margin: -10vh auto 0 auto; |
|
||||
position: relative; |
|
||||
z-index: 1; |
|
||||
padding: 20px; |
|
||||
box-sizing: border-box; |
|
||||
overflow: auto; |
|
||||
|
|
||||
&-title { |
|
||||
font-size: 20px; |
|
||||
margin-bottom: 10px; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
|
|
||||
&-description { |
|
||||
font-size: 16px; |
|
||||
line-height: 30px; |
|
||||
text-align: justify; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
&-footer { |
|
||||
background: white; |
|
||||
height: 10vh; |
|
||||
display: flex; |
|
||||
padding: 20px 30px; |
|
||||
box-sizing: border-box; |
|
||||
justify-content: space-between; |
|
||||
align-items: center; |
|
||||
gap: 20px; |
|
||||
|
|
||||
&-price { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
font-size: 20px; |
|
||||
gap: 10px; |
|
||||
|
|
||||
&-iconContainer { |
|
||||
width: 35px; |
|
||||
height: 35px; |
|
||||
border: 1px solid #86A8FF; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
background: rgba(75, 129, 251, 0.1); |
|
||||
border-radius: 100%; |
|
||||
|
|
||||
&-img { |
|
||||
width: 20px; |
|
||||
height: 20px; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,14 +0,0 @@ |
|||||
//选举结果 |
|
||||
<template> |
|
||||
|
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'; |
|
||||
import { reactive, ref } from 'vue'; |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,12 +0,0 @@ |
|||||
//个人信息 |
|
||||
<template> |
|
||||
|
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { reactive, ref } from 'vue'; |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,14 +0,0 @@ |
|||||
//我的选举 |
|
||||
<template> |
|
||||
|
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { reactive, ref } from 'vue'; |
|
||||
|
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,368 +0,0 @@ |
|||||
<script setup lang="ts"> |
|
||||
import { onShow } from '@dcloudio/uni-app'; |
|
||||
import { log } from 'console'; |
|
||||
import { |
|
||||
onMounted, |
|
||||
ref |
|
||||
} from 'vue'; |
|
||||
import PullToRefresh from '@/components/PullToRefresh.vue'; |
|
||||
|
|
||||
const tpList = ref([ |
|
||||
{ |
|
||||
img: '/static/img/grxx.png', |
|
||||
name: '陈志远', |
|
||||
class: '现任财务总监', |
|
||||
} |
|
||||
]) |
|
||||
|
|
||||
const doSearch = (_formData : { page : number; limit : number }, onSuccess : Function) => { |
|
||||
// const submitData = { ...formData } |
|
||||
// listApi(submitData, userStore.useType).then((res) => { |
|
||||
// const { data } = res as { data: { data: any; total: number } } |
|
||||
// onSuccess({ data }) |
|
||||
// }) |
|
||||
onSuccess({ |
|
||||
data: { |
|
||||
data: [ |
|
||||
{ |
|
||||
img: '/static/img/grxx.png', |
|
||||
name: '陈志远', |
|
||||
class: '现任财务总监', |
|
||||
}, |
|
||||
{ |
|
||||
img: '/static/img/grxx.png', |
|
||||
name: '陈志远', |
|
||||
class: '现任财务总监', |
|
||||
}, |
|
||||
{ |
|
||||
img: '/static/img/grxx.png', |
|
||||
name: '陈志远', |
|
||||
class: '现任财务总监', |
|
||||
}, |
|
||||
{ |
|
||||
img: '/static/img/grxx.png', |
|
||||
name: '陈志远', |
|
||||
class: '现任财务总监', |
|
||||
}, |
|
||||
{ |
|
||||
img: '/static/img/grxx.png', |
|
||||
name: '陈志远', |
|
||||
class: '现任财务总监', |
|
||||
} |
|
||||
], |
|
||||
total: 0 |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const selectIndex = ref(0) |
|
||||
const buttlist = ref([ |
|
||||
{ |
|
||||
butname: '同意' |
|
||||
}, |
|
||||
{ |
|
||||
butname: '反对' |
|
||||
}, |
|
||||
{ |
|
||||
butname: '弃权' |
|
||||
} |
|
||||
]) |
|
||||
|
|
||||
const selectBut = (index : number) => { |
|
||||
selectIndex.value = index |
|
||||
} |
|
||||
|
|
||||
const loadData = async () => { |
|
||||
// 模拟异步请求 |
|
||||
console.log(1111111111111) |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<pull-to-refresh :on-refresh="loadData"> |
|
||||
<!-- 你的页面内容 --> |
|
||||
<view class="box"> |
|
||||
<ex-list ref="reListRef" custom-list-type="scroll" :on-form-search="doSearch" empty-text="" |
|
||||
customListType="custom"> |
|
||||
<template v-slot="{ data }"> |
|
||||
|
|
||||
<view class="headpart"> |
|
||||
<view class="title"> |
|
||||
2024年度董事会成员选举 |
|
||||
</view> |
|
||||
<view class="time"> |
|
||||
投票开始时间:2024年3月15日 18:00 |
|
||||
</view> |
|
||||
<view class="time"> |
|
||||
投票截止时间:2024年3月15日 18:00 |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="tppart"> |
|
||||
<view class="tpone" v-for="(row, index) of data" :key="index"> |
|
||||
<view class="topp"> |
|
||||
<img style="width: 96rpx;height: 96rpx; border-radius: 50%;" :src="row.img" alt="" /> |
|
||||
<view class="rightpart"> |
|
||||
<view class="name"> |
|
||||
{{ row.name }} |
|
||||
</view> |
|
||||
<view class="class"> |
|
||||
{{ row.class }} |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="bottomp"> |
|
||||
<view class="minbut" v-for="(item,index) in buttlist" :key="index" |
|
||||
@click="selectBut(index)" :class="{active: selectIndex === index}"> |
|
||||
{{item.butname}} |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
</ex-list> |
|
||||
<view class="bottbutton"> |
|
||||
<view class="qbty"> |
|
||||
全部同意 |
|
||||
</view> |
|
||||
<view class="tjtp"> |
|
||||
提交投票 |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</pull-to-refresh> |
|
||||
</template> |
|
||||
|
|
||||
<style scoped lang="scss"> |
|
||||
.box { |
|
||||
width: 100%; |
|
||||
height: 100vh; |
|
||||
background-color: #F9FAFB; |
|
||||
|
|
||||
.headpart { |
|
||||
width: 86%; |
|
||||
height: 194rpx; |
|
||||
border-radius: 24rpx; |
|
||||
background-color: #EFF6FF; |
|
||||
margin: 32rpx auto; |
|
||||
padding: 20rpx 3%; |
|
||||
|
|
||||
|
|
||||
.title { |
|
||||
color: #2563EB; |
|
||||
font-size: 28rpx; |
|
||||
margin-top: 16rpx; |
|
||||
} |
|
||||
|
|
||||
.time { |
|
||||
margin-top: 16rpx; |
|
||||
color: #4B5563; |
|
||||
font-size: 28rpx; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.tppart { |
|
||||
width: 100%; |
|
||||
max-height: 69vh; |
|
||||
overflow-y: auto; |
|
||||
display: grid; |
|
||||
justify-items: center; |
|
||||
|
|
||||
.tpone { |
|
||||
width: 91%; |
|
||||
height: 264rpx; |
|
||||
padding: 20rpx 4%; |
|
||||
box-sizing: border-box; |
|
||||
border-radius: 24rpx; |
|
||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.001), rgba(0, 0, 0, 0.001)), #FFFFFF; |
|
||||
box-sizing: border-box; |
|
||||
border: 2rpx solid #F3F4F6; |
|
||||
box-shadow: 0rpx 2rpx 4rpx -2rpx rgba(0, 0, 0, 0.1), 0rpx 2rpx 6rpx 0rpx rgba(0, 0, 0, 0.1); |
|
||||
margin-top: 32rpx; |
|
||||
display: grid; |
|
||||
|
|
||||
.topp { |
|
||||
display: flex; |
|
||||
|
|
||||
.rightpart { |
|
||||
margin-left: 32rpx; |
|
||||
display: grid; |
|
||||
justify-items: left; |
|
||||
align-content: baseline; |
|
||||
|
|
||||
.name { |
|
||||
font-family: Roboto; |
|
||||
font-size: 28rpx; |
|
||||
font-weight: 500; |
|
||||
line-height: 42rpx; |
|
||||
letter-spacing: normal; |
|
||||
color: #000000; |
|
||||
margin-top: 7rpx; |
|
||||
} |
|
||||
|
|
||||
.class { |
|
||||
font-family: Roboto; |
|
||||
font-size: 28rpx; |
|
||||
font-weight: normal; |
|
||||
line-height: 40rpx; |
|
||||
letter-spacing: normal; |
|
||||
color: #6B7280; |
|
||||
margin-top: 7rpx; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.bottomp { |
|
||||
display: flex; |
|
||||
justify-content: space-between; |
|
||||
gap: 0rpx 20rpx; |
|
||||
|
|
||||
.minbut { |
|
||||
flex: 1; |
|
||||
width: 190rpx; |
|
||||
height: 76rpx; |
|
||||
/* 自动布局 */ |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
padding: 16rpx 32rpx; |
|
||||
flex-wrap: wrap; |
|
||||
align-content: flex-start; |
|
||||
border-radius: 8rpx; |
|
||||
background: #FFFFFF; |
|
||||
box-sizing: border-box; |
|
||||
border: 2rpx solid #D1D5DB; |
|
||||
font-family: Roboto; |
|
||||
font-size: 28rpx; |
|
||||
font-weight: normal; |
|
||||
line-height: 40rpx; |
|
||||
text-align: center; |
|
||||
letter-spacing: normal; |
|
||||
color: #4B5563; |
|
||||
} |
|
||||
|
|
||||
.minbut.active { |
|
||||
border: 2rpx solid #2563EB; |
|
||||
color: #2563EB; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
.tpone:first-child { |
|
||||
margin-top: 0; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.bottbutton { |
|
||||
width: 100%; |
|
||||
height: 10vh; |
|
||||
display: flex; |
|
||||
padding: 24rpx 32rpx; |
|
||||
gap: 0rpx 24rpx; |
|
||||
flex-wrap: wrap; |
|
||||
align-content: flex-start; |
|
||||
background: #FFFFFF; |
|
||||
box-sizing: border-box; |
|
||||
border-width: 2rpx 0rpx 0rpx 0rpx; |
|
||||
border-style: solid; |
|
||||
border-color: #F3F4F6; |
|
||||
position: fixed; |
|
||||
bottom: 0; |
|
||||
|
|
||||
.qbty { |
|
||||
width: 331rpx; |
|
||||
height: 90rpx; |
|
||||
/* 自动布局 */ |
|
||||
display: flex; |
|
||||
box-sizing: border-box; |
|
||||
justify-content: center; |
|
||||
padding: 24rpx 0rpx; |
|
||||
gap: 0rpx 20rpx; |
|
||||
flex-wrap: wrap; |
|
||||
border-radius: 8rpx; |
|
||||
background: #EFF6FF; |
|
||||
font-family: Roboto; |
|
||||
font-size: 28rpx; |
|
||||
font-weight: 500; |
|
||||
line-height: 42rpx; |
|
||||
text-align: center; |
|
||||
letter-spacing: normal; |
|
||||
color: #2563EB; |
|
||||
} |
|
||||
|
|
||||
.tjtp { |
|
||||
width: 331rpx; |
|
||||
height: 90rpx; |
|
||||
/* 自动布局 */ |
|
||||
display: flex; |
|
||||
box-sizing: border-box; |
|
||||
justify-content: center; |
|
||||
padding: 24rpx 0rpx; |
|
||||
gap: 0rpx 20rpx; |
|
||||
flex-wrap: wrap; |
|
||||
border-radius: 8rpx; |
|
||||
background: #2563EB; |
|
||||
font-family: Roboto; |
|
||||
font-size: 28rpx; |
|
||||
font-weight: 500; |
|
||||
line-height: 42rpx; |
|
||||
text-align: center; |
|
||||
letter-spacing: normal; |
|
||||
color: #FFFFFF; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.address-items { |
|
||||
padding: 20rpx 15rpx 32rpx 28rpx; |
|
||||
background-color: #fff; |
|
||||
border-bottom: 2rpx solid #f5f5f5; |
|
||||
|
|
||||
.left { |
|
||||
flex: 1; |
|
||||
overflow: hidden; |
|
||||
|
|
||||
.name { |
|
||||
font-size: 28rpx; |
|
||||
font-weight: 700; |
|
||||
color: #101010; |
|
||||
line-height: 40rpx; |
|
||||
margin-right: 16rpx; |
|
||||
} |
|
||||
|
|
||||
.isdefault { |
|
||||
font-size: 20rpx; |
|
||||
font-weight: 400; |
|
||||
color: #fff; |
|
||||
padding: 4rpx 12rpx; |
|
||||
border-radius: 8rpx; |
|
||||
background: linear-gradient(90deg, #4778ff 0%, #4778ffb8 100%); |
|
||||
} |
|
||||
|
|
||||
.info { |
|
||||
width: 100%; |
|
||||
color: #666; |
|
||||
font-size: 24rpx; |
|
||||
font-weight: 400; |
|
||||
margin-top: 12rpx; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.right { |
|
||||
width: 140rpx; |
|
||||
padding-left: 32rpx; |
|
||||
font-size: 24rpx; |
|
||||
font-weight: 400; |
|
||||
color: #4979ff; |
|
||||
text-align: right; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.buts { |
|
||||
width: 100%; |
|
||||
height: 10vh; |
|
||||
background-color: F3F4F6; |
|
||||
position: fixed; |
|
||||
bottom: 0; |
|
||||
border-top: 2rpx solid #ebebec; |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,33 +0,0 @@ |
|||||
<template> |
|
||||
<view :style="themeColor()"> |
|
||||
<u-icon name="arrow-left" class="navigate-back" @click="navigateBack"></u-icon> |
|
||||
<web-view :src="src"></web-view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { onLoad } from '@dcloudio/uni-app'; |
|
||||
import { ref } from 'vue'; |
|
||||
|
|
||||
const src = ref('') |
|
||||
|
|
||||
onLoad((option : any) => { |
|
||||
src.value = decodeURIComponent(option.src); |
|
||||
}) |
|
||||
|
|
||||
const navigateBack = () => { |
|
||||
uni.navigateBack({ |
|
||||
delta: 1 |
|
||||
}); |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.navigate-back { |
|
||||
position: absolute; |
|
||||
top: 34rpx; |
|
||||
left: 34rpx; |
|
||||
z-index: 999; |
|
||||
font-size: 16px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,138 +0,0 @@ |
|||||
import { defineStore } from 'pinia' |
|
||||
import { toRaw } from 'vue' |
|
||||
import { diyRedirect, currRoute, getToken } from '@/utils/common'; |
|
||||
import { useLogin } from '@/hooks/useLogin'; |
|
||||
|
|
||||
interface Diy { |
|
||||
mode: string, // 模式:decorate 装修,为空表示正常
|
|
||||
pageMode: string, // 页面展示模式,diy:自定义,fixed:固定
|
|
||||
currentIndex: number, |
|
||||
global: { |
|
||||
title: string, |
|
||||
pageStartBgColor: string, // 页面背景颜色(开始)
|
|
||||
pageEndBgColor: string, // 页面背景颜色(结束)
|
|
||||
bottomTabBarSwitch: boolean, // 底部导航开关
|
|
||||
bgUrl: string |
|
||||
}, |
|
||||
// 组件集合
|
|
||||
value: any[], |
|
||||
topFixedStatus: string, // 置顶组件的状态
|
|
||||
scrollTop: number, |
|
||||
topTabarHeight: number |
|
||||
} |
|
||||
|
|
||||
const useDiyStore = defineStore('diy', { |
|
||||
state: (): Diy => { |
|
||||
return { |
|
||||
mode: '', |
|
||||
pageMode: 'diy', |
|
||||
currentIndex: -99, |
|
||||
global: { |
|
||||
title: "", |
|
||||
pageStartBgColor: '', // 页面背景颜色(开始)
|
|
||||
pageEndBgColor: '', // 页面背景颜色(结束)
|
|
||||
bottomTabBarSwitch: true, |
|
||||
bgUrl: '' |
|
||||
}, |
|
||||
value: [], // 组件集合
|
|
||||
topFixedStatus: 'home', // 顶部 置顶组件状态,home:展示首页数据、diy:展示置顶组件定义的子页面
|
|
||||
scrollTop: 0, // 滚动位置
|
|
||||
topTabarHeight: 0 |
|
||||
} |
|
||||
}, |
|
||||
getters: {}, |
|
||||
actions: { |
|
||||
// 初始化
|
|
||||
init() { |
|
||||
// #ifdef H5
|
|
||||
var data = JSON.stringify({ |
|
||||
type: 'init', |
|
||||
load: true |
|
||||
}); |
|
||||
// 传输给后台数据
|
|
||||
window.parent.postMessage(data, '*'); |
|
||||
|
|
||||
// 监听父页面发来的消息
|
|
||||
window.addEventListener('message', event => { |
|
||||
try { |
|
||||
let data = JSON.parse(event.data); |
|
||||
this.currentIndex = data.currentIndex; |
|
||||
this.pageMode = data.pageMode; |
|
||||
if (data.global) this.global = data.global; |
|
||||
if (data.value) this.value = data.value; |
|
||||
|
|
||||
if (this.value) { |
|
||||
this.value.forEach((item, index) => { |
|
||||
item.pageStyle = ''; |
|
||||
if (item.pageStartBgColor) { |
|
||||
if (item.pageStartBgColor && item.pageEndBgColor) item.pageStyle += `background:linear-gradient(${ item.pageGradientAngle },${ item.pageStartBgColor },${ item.pageEndBgColor });`; |
|
||||
else item.pageStyle += 'background-color:' + item.pageStartBgColor + ';'; |
|
||||
} |
|
||||
|
|
||||
if (item.margin) { |
|
||||
if (item.margin.top > 0) { |
|
||||
item.pageStyle += 'padding-top:' + item.margin.top * 2 + 'rpx' + ';'; |
|
||||
} else { |
|
||||
item.pageStyle += 'padding-top:2rpx' + ';'; // 装修实时预览需要设置
|
|
||||
} |
|
||||
item.pageStyle += 'padding-bottom:' + item.margin.bottom * 2 + 'rpx' + ';'; |
|
||||
item.pageStyle += 'padding-right:' + item.margin.both * 2 + 'rpx' + ';'; |
|
||||
item.pageStyle += 'padding-left:' + item.margin.both * 2 + 'rpx' + ';'; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
// console.log('uniapp 接受后台装修返回的组件数据', data);
|
|
||||
} catch (e) { |
|
||||
console.log('uni-app diy 接受数据错误', e) |
|
||||
} |
|
||||
}, false); |
|
||||
// #endif
|
|
||||
}, |
|
||||
// 将数据传输给后台
|
|
||||
postMessage(index: any, component: any) { |
|
||||
// #ifdef H5
|
|
||||
this.currentIndex = index; |
|
||||
if (component) |
|
||||
var data: any = JSON.stringify({ |
|
||||
type: 'data', |
|
||||
index: this.currentIndex, |
|
||||
global: toRaw(this.global), |
|
||||
value: toRaw(this.value), |
|
||||
component: toRaw(component) |
|
||||
}); |
|
||||
// 传输给后台数据
|
|
||||
window.parent.postMessage(data, '*'); |
|
||||
// #endif
|
|
||||
}, |
|
||||
// 选中正在编辑的组件
|
|
||||
changeCurrentIndex(index: number, component: any = null) { |
|
||||
// #ifdef H5
|
|
||||
|
|
||||
// 实际展示禁止编辑
|
|
||||
if (this.mode == '') return; |
|
||||
|
|
||||
// 减少重复请求
|
|
||||
if (this.currentIndex == index) return; |
|
||||
this.currentIndex = index; |
|
||||
var data = JSON.stringify({ |
|
||||
type: 'change', |
|
||||
index, |
|
||||
component: toRaw(component) |
|
||||
}); |
|
||||
window.parent.postMessage(data, '*'); |
|
||||
// #endif
|
|
||||
}, |
|
||||
toRedirect(data: any) { |
|
||||
if (Object.keys(data).length) { |
|
||||
if (!data.name) return; |
|
||||
if (currRoute() == 'app/pages/member/index' && !getToken()) { |
|
||||
useLogin().setLoginBack({ url: data.url }) |
|
||||
return; |
|
||||
} |
|
||||
diyRedirect(data); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
export default useDiyStore |
|
||||
@ -1,56 +0,0 @@ |
|||||
<!-- components/PullToRefresh.vue --> |
|
||||
<template> |
|
||||
<scroll-view |
|
||||
scroll-y |
|
||||
:refresher-enabled="true" |
|
||||
:refresher-triggered="isRefreshing" |
|
||||
@refresherrefresh="handleRefresh" |
|
||||
class="scroll-view" |
|
||||
> |
|
||||
<!-- 下拉刷新提示区域 --> |
|
||||
<view v-if="isRefreshing" class="refresh-loading"> |
|
||||
<text>加载中...</text> |
|
||||
</view> |
|
||||
|
|
||||
<!-- 内容插槽 --> |
|
||||
<slot /> |
|
||||
</scroll-view> |
|
||||
</template> |
|
||||
|
|
||||
<script setup> |
|
||||
import { ref } from 'vue'; |
|
||||
|
|
||||
const props = defineProps({ |
|
||||
onRefresh: { |
|
||||
type: Function, |
|
||||
required: true |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
const isRefreshing = ref(false); |
|
||||
|
|
||||
const handleRefresh = async () => { |
|
||||
if (isRefreshing.value) return; |
|
||||
|
|
||||
isRefreshing.value = true; |
|
||||
try { |
|
||||
await props.onRefresh(); |
|
||||
} finally { |
|
||||
isRefreshing.value = false; |
|
||||
} |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.scroll-view { |
|
||||
height: 100vh; |
|
||||
box-sizing: border-box; |
|
||||
} |
|
||||
.refresh-loading { |
|
||||
height: 100rpx; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: center; |
|
||||
color: #666; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,154 +0,0 @@ |
|||||
<template> |
|
||||
<u-popup :show="show" @close="show = false" mode="bottom" :round="10" :closeable="true"> |
|
||||
<view class="text-center p-[30rpx]">请选择地区</view> |
|
||||
|
|
||||
<view class="flex p-[30rpx] text-sm font-semibold"> |
|
||||
<view v-if="areaList.province.length" class="flex-1" :class="{'text-[var(--primary-color)]': currSelect == 'province'}" @click="currSelect = 'province'"> |
|
||||
<view v-if="selected.province">{{ selected.province.name }}</view> |
|
||||
<view v-else>请选择</view> |
|
||||
</view> |
|
||||
<view v-if="areaList.city.length" class="flex-1" :class="{'text-[var(--primary-color)]': currSelect == 'city' }" @click="currSelect = 'city'"> |
|
||||
<view v-if="selected.city">{{ selected.city.name }}</view> |
|
||||
<view v-else>请选择</view> |
|
||||
</view> |
|
||||
<view v-if="areaList.district.length" class="flex-1" :class="{'text-[var(--primary-color)]': currSelect == 'district' }" @click="currSelect = 'district'"> |
|
||||
<view v-if="selected.district">{{ selected.district.name }}</view> |
|
||||
<view v-else>请选择</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<scroll-view scroll-y="true" class="h-[50vh]"> |
|
||||
<view class="flex p-[30rpx] pt-0 text-sm"> |
|
||||
<view v-if="areaList.province.length" v-show="currSelect == 'province'"> |
|
||||
<view v-for="item in areaList.province" class="leading-loose" :class="{'text-[var(--primary-color)]': selected.province && selected.province.id == item.id }" |
|
||||
@click="selected.province = item" >{{ item.name }}</view> |
|
||||
</view> |
|
||||
<view v-if="areaList.city.length" v-show="currSelect == 'city'"> |
|
||||
<view v-for="item in areaList.city" class="leading-loose" :class="{'text-[var(--primary-color)]': selected.city && selected.city.id == item.id }" |
|
||||
@click="selected.city = item">{{ item.name }}</view> |
|
||||
</view> |
|
||||
<view v-if="areaList.district.length" v-show="currSelect == 'district'"> |
|
||||
<view v-for="item in areaList.district" class="leading-loose" :class="{'text-[var(--primary-color)]': selected.district && selected.district.id == item.id }" |
|
||||
@click="selected.district = item">{{ item.name }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</scroll-view> |
|
||||
</u-popup> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, watch } from 'vue' |
|
||||
import { getAreaListByPid, getAreaByCode } from '@/app/api/system' |
|
||||
|
|
||||
const prop = defineProps({ |
|
||||
areaId: { |
|
||||
type: Number, |
|
||||
default: 0 |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
const show = ref(false) |
|
||||
const areaList = reactive({ |
|
||||
province: [], |
|
||||
city: [], |
|
||||
district: [] |
|
||||
}) |
|
||||
const currSelect = ref('province') |
|
||||
|
|
||||
const selected = reactive({ |
|
||||
province: null, |
|
||||
city: null, |
|
||||
district: null |
|
||||
}) |
|
||||
|
|
||||
getAreaListByPid(0).then(({ data }) => { |
|
||||
areaList.province = data |
|
||||
}).catch() |
|
||||
|
|
||||
watch(() => prop.areaId, (nval, oval)=> { |
|
||||
if (nval && !oval) { |
|
||||
getAreaByCode(nval).then(({ data }) => { |
|
||||
data.province && (selected.province = data.province) |
|
||||
data.city && (selected.city = data.city) |
|
||||
data.district && (selected.district = data.district) |
|
||||
}) |
|
||||
.catch() |
|
||||
} |
|
||||
},{ |
|
||||
immediate:true |
|
||||
}) |
|
||||
|
|
||||
/** |
|
||||
* 监听省变更 |
|
||||
*/ |
|
||||
watch(() => selected.province, ()=> { |
|
||||
getAreaListByPid(selected.province.id).then(({ data }) => { |
|
||||
areaList.city = data |
|
||||
currSelect.value = 'city' |
|
||||
|
|
||||
if (selected.city) { |
|
||||
let isExist = false |
|
||||
for (let i = 0; i < data.length; i++) { |
|
||||
if (selected.city.id == data[i].id) { |
|
||||
isExist = true |
|
||||
break |
|
||||
} |
|
||||
} |
|
||||
if (!isExist) { |
|
||||
selected.city = null |
|
||||
} |
|
||||
} |
|
||||
}).catch() |
|
||||
}, { deep: true }) |
|
||||
|
|
||||
/** |
|
||||
* 监听市变更 |
|
||||
*/ |
|
||||
watch(() => selected.city, (nval)=> { |
|
||||
if (nval) { |
|
||||
getAreaListByPid(selected.city.id).then(({ data }) => { |
|
||||
areaList.district = data |
|
||||
currSelect.value = 'district' |
|
||||
|
|
||||
if (selected.district) { |
|
||||
let isExist = false |
|
||||
for (let i = 0; i < data.length; i++) { |
|
||||
if (selected.district.id == data[i].id) { |
|
||||
isExist = true |
|
||||
break |
|
||||
} |
|
||||
} |
|
||||
if (!isExist) { |
|
||||
selected.district = null |
|
||||
} |
|
||||
} |
|
||||
}).catch() |
|
||||
} else { |
|
||||
areaList.district = [] |
|
||||
selected.district = null |
|
||||
} |
|
||||
|
|
||||
}, { deep: true }) |
|
||||
|
|
||||
const emits = defineEmits(['complete']) |
|
||||
|
|
||||
/** |
|
||||
* 监听区县变更 |
|
||||
*/ |
|
||||
watch(() => selected.district, (nval)=> { |
|
||||
if (nval) { |
|
||||
currSelect.value = 'district' |
|
||||
emits('complete', selected) |
|
||||
show.value = false |
|
||||
} |
|
||||
}, { deep: true }) |
|
||||
|
|
||||
const open = ()=> { |
|
||||
show.value = true |
|
||||
} |
|
||||
|
|
||||
defineExpose({ |
|
||||
open |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,117 +0,0 @@ |
|||||
<template> |
|
||||
<u-popup :show="show" :round="10" @close="show = false" :closeable="true"> |
|
||||
<view class="mx-[30rpx] pb-[20rpx] pt-[40rpx] border-t"> |
|
||||
<view class="text-base">{{ t('getAvatarNickname') }}</view> |
|
||||
<view class="text-sm mt-[18rpx] text-gray-400">{{ t('getAvatarNicknameTips') }}</view> |
|
||||
</view> |
|
||||
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef"> |
|
||||
<view class="mx-[30rpx]"> |
|
||||
<view class="mt-[20rpx]"> |
|
||||
<u-form-item :label="t('headimg')" prop="headimg" :border-bottom="true"> |
|
||||
<button class="m-0 my-[10rpx] p-0 w-[140rpx] h-[140rpx]" open-type="chooseAvatar" @chooseavatar="onChooseAvatar"> |
|
||||
<view class="w-full h-full flex items-center justify-center overflow-hidden"> |
|
||||
<u-image :src="img(formData.headimg)" width="140rpx" height="140rpx" v-if="formData.headimg" mode="aspectFill"></u-image> |
|
||||
<u-icon name="plus" v-else></u-icon> |
|
||||
</view> |
|
||||
</button> |
|
||||
</u-form-item> |
|
||||
<u-form-item :label=" t('nickname')" prop="nickname" :border-bottom="true"> |
|
||||
<input type="nickname" v-model="formData.nickname" :placeholder="t('nicknamePlaceholder')" @blur="bindNickname"> |
|
||||
</u-form-item> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="p-[30rpx] mt-[20rpx]"> |
|
||||
<u-button type="primary" :loading="loading" :text="t('confirm')" shape="circle" @click="confirm"></u-button> |
|
||||
</view> |
|
||||
</u-form> |
|
||||
</u-popup> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, reactive, computed, watch } from 'vue' |
|
||||
import { t } from '@/locale' |
|
||||
import useMemberStore from '@/stores/member' |
|
||||
import { img } from '@/utils/common' |
|
||||
import { modifyMember } from '@/app/api/member' |
|
||||
import { fetchBase64Image } from '@/app/api/system' |
|
||||
|
|
||||
const show = ref(false) |
|
||||
const loading = ref(false) |
|
||||
const memberStore = useMemberStore() |
|
||||
const info = computed(() => memberStore.info) |
|
||||
|
|
||||
const formData = reactive({ |
|
||||
nickname: '', |
|
||||
headimg: '' |
|
||||
}) |
|
||||
|
|
||||
watch(() => info.value, () => { |
|
||||
if (info.value) { |
|
||||
formData.nickname = info.value.nickname |
|
||||
formData.headimg = info.value.headimg |
|
||||
} |
|
||||
}, { immediate: true }) |
|
||||
|
|
||||
const onChooseAvatar = (e) => { |
|
||||
uni.getFileSystemManager().readFile({ |
|
||||
filePath: e.detail.avatarUrl, //选择图片返回的相对路径 |
|
||||
encoding: 'base64', //编码格式 |
|
||||
success: res => { |
|
||||
fetchBase64Image({ content: res.data }).then(uploadRes => { |
|
||||
formData.headimg = uploadRes.data.url |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
const bindNickname = (e) => { |
|
||||
formData.nickname = e.detail.value |
|
||||
} |
|
||||
|
|
||||
const rules = { |
|
||||
'headimg': { |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('headimgPlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
}, |
|
||||
'nickname': { |
|
||||
type: 'string', |
|
||||
required: true, |
|
||||
message: t('nicknamePlaceholder'), |
|
||||
trigger: ['blur', 'change'], |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const formRef = ref(null) |
|
||||
|
|
||||
const confirm = async () => { |
|
||||
formRef.value.validate().then(async() => { |
|
||||
if (loading.value) return |
|
||||
loading.value = true |
|
||||
|
|
||||
// 修改头像 |
|
||||
await modifyMember({ field: 'headimg', value: formData.headimg }).then(() => { |
|
||||
memberStore.info.headimg = formData.headimg |
|
||||
}).catch(() => { |
|
||||
loading.value = false |
|
||||
}) |
|
||||
if (!loading.value) return |
|
||||
|
|
||||
// 修改昵称 |
|
||||
modifyMember({ field: 'nickname', value: formData.nickname }).then(() => { |
|
||||
memberStore.info.nickname = formData.nickname |
|
||||
loading.value = false |
|
||||
show.value = false |
|
||||
}).catch(() => { |
|
||||
loading.value = false |
|
||||
}) |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
defineExpose({ |
|
||||
show |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,22 +0,0 @@ |
|||||
const version = '3' |
|
||||
|
|
||||
// 开发环境才提示,生产环境不会提示
|
|
||||
if (process.env.NODE_ENV === 'development') { |
|
||||
console.log(`\n %c lxui-uni V${version} %c https://blog.csdn.net/qq_51091386/article/details/138125947 \n\n`, 'color: #ffffff; background: #3c9cff; padding:5px 0;', 'color: #3c9cff;background: #ffffff; padding:5px 0;'); |
|
||||
} |
|
||||
|
|
||||
export let uploadUrl = '/api/v1.Resources/upload' |
|
||||
export let uploadBaseUrl = '' |
|
||||
const setConfig = (config: any) => { |
|
||||
console.log(config) |
|
||||
if (config?.uploadUrl) { |
|
||||
uploadUrl = config.uploadUrl |
|
||||
} |
|
||||
if (config?.uploadBaseUrl) { |
|
||||
uploadBaseUrl = config.uploadBaseUrl |
|
||||
} |
|
||||
} |
|
||||
export default { |
|
||||
version, |
|
||||
setConfig |
|
||||
} |
|
||||
@ -1,145 +0,0 @@ |
|||||
/* |
|
||||
* @description: 分页请求 |
|
||||
* @fileName: useListLoadClass.ts |
|
||||
* @author: lxx |
|
||||
* @date: 2023-07-08 08:55:52 |
|
||||
* @version: V1.0.0 |
|
||||
*/ |
|
||||
import { reactive, ref, computed } from "vue" |
|
||||
import { onReachBottom } from "@dcloudio/uni-app" |
|
||||
|
|
||||
class LoadDataClass { |
|
||||
// 请求参数
|
|
||||
static queryParams = reactive({ |
|
||||
page: 1, |
|
||||
limit: 10 |
|
||||
}) |
|
||||
// 列表数据
|
|
||||
list = ref<any[]>([]) |
|
||||
total = ref(0) |
|
||||
// 前置处理方法
|
|
||||
afterLoadData: Function | undefined |
|
||||
// 请求方法
|
|
||||
Query: Function |
|
||||
// 加载状态参数
|
|
||||
isLoading = ref(false) |
|
||||
// 无更多数据了
|
|
||||
isNoData = computed(() => { |
|
||||
if (LoadDataClass.queryParams.page * LoadDataClass.queryParams.limit >= this.total.value) { |
|
||||
return true |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
// 显示暂无数据
|
|
||||
isEmpty = computed(() => { |
|
||||
if (this.total.value === 0) { |
|
||||
return true |
|
||||
} else { |
|
||||
return false |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
constructor(apiFunctions: Function, afterLoadData?: Function, options: any = {}) { |
|
||||
this.queryParamsReset() |
|
||||
this.Query = apiFunctions |
|
||||
this.afterLoadData = afterLoadData |
|
||||
// console.log('options', options)
|
|
||||
// 存在额外参数拼接
|
|
||||
this.setParams(options) |
|
||||
} |
|
||||
// 加载数据
|
|
||||
LoadData = async () => { |
|
||||
uni.showLoading({ |
|
||||
title: '加载中...' |
|
||||
}) |
|
||||
this.isLoading.value = true |
|
||||
const res = await this.Query(LoadDataClass.queryParams) |
|
||||
this.afterLoadData && this.afterLoadData(res) |
|
||||
this.total.value = res.data.total |
|
||||
this.list.value = this.list.value.concat(res.data.data) |
|
||||
|
|
||||
uni.hideLoading() |
|
||||
uni.stopPullDownRefresh() |
|
||||
this.isLoading.value = false |
|
||||
} |
|
||||
/** |
|
||||
* 添加额外参数刷新 |
|
||||
* @param options: 参数 |
|
||||
* @param isClear: 是否清空数据 false |
|
||||
*/ |
|
||||
setParams = (options: any, isClear: boolean = false) => { |
|
||||
if (isClear) { |
|
||||
this.queryParamsReset() |
|
||||
} else { |
|
||||
LoadDataClass.queryParams.page = 1 |
|
||||
} |
|
||||
this.list.value = [] |
|
||||
LoadDataClass.queryParams = Object.assign(LoadDataClass.queryParams, options) |
|
||||
// 加载数据
|
|
||||
this.LoadData() |
|
||||
} |
|
||||
// 加载更多
|
|
||||
LoadMore = () => { |
|
||||
if (this.isNoData.value || this.isLoading.value) return // 无数据或者加载中不进行加载
|
|
||||
LoadDataClass.queryParams.page += 1 |
|
||||
this.LoadData() |
|
||||
} |
|
||||
// 重置参数
|
|
||||
queryParamsReset = () => { |
|
||||
LoadDataClass.queryParams = reactive({ |
|
||||
page: 1, |
|
||||
limit: 10 |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 刷新 |
|
||||
* @param isClear: 是否清空数据 |
|
||||
*/ |
|
||||
ReLoad = (isClear: boolean = false) => { |
|
||||
this.isLoading.value = false |
|
||||
this.list.value = [] |
|
||||
if (isClear) { |
|
||||
this.queryParamsReset() |
|
||||
} else { |
|
||||
LoadDataClass.queryParams.page = 1 |
|
||||
} |
|
||||
this.LoadData() |
|
||||
} |
|
||||
} |
|
||||
/** |
|
||||
* 分页加载数据方法 |
|
||||
* @param api: ListAPI 方法 |
|
||||
* @param afterLoadData: res数据前置处理方法 |
|
||||
* @returns |
|
||||
*/ |
|
||||
interface LoadDataInt { |
|
||||
api: Function |
|
||||
afterLoadData?: Function |
|
||||
options?: any |
|
||||
isNeedReachBottom?: boolean |
|
||||
} |
|
||||
|
|
||||
export function LoadData({ api, afterLoadData, options, isNeedReachBottom = true }: LoadDataInt) { |
|
||||
const data = new LoadDataClass(api, afterLoadData, options) |
|
||||
|
|
||||
// 下拉加载
|
|
||||
if (isNeedReachBottom) { |
|
||||
onReachBottom(() => { |
|
||||
console.log('onReachBottom') |
|
||||
data.LoadMore() |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
return { |
|
||||
list: data.list, |
|
||||
isLoading: data.isLoading, |
|
||||
isNoData: data.isNoData, |
|
||||
isEmpty: data.isEmpty, |
|
||||
ReLoad: data.ReLoad, |
|
||||
setParams: data.setParams, |
|
||||
LoadMore: data.LoadMore |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@ -1,294 +0,0 @@ |
|||||
/** |
|
||||
* 公共跳转方法 |
|
||||
* @author liux |
|
||||
* @date 2023-08-15 14:17 |
|
||||
* @param { string } url 跳转路径 |
|
||||
* @param { "navigateTo" | "redirectTo" | "reLaunch" | "switchTab" } [mode=navigateTo] 跳转模式 |
|
||||
* @param { object } params 跳转传参 |
|
||||
* @example |
|
||||
* goToPage({ url: 'pages/index/index', mode: 'navigateTo', params: {'id': 1} }) |
|
||||
* @returns { void } |
|
||||
*/ |
|
||||
type pageMode = 'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab' |
|
||||
|
|
||||
interface goToPageInt { |
|
||||
url: string |
|
||||
mode?: pageMode |
|
||||
params?: { |
|
||||
[n: string]: string | number | boolean |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
export const goToPage = ({ url, mode = 'navigateTo', params = {} }: goToPageInt): void => { |
|
||||
if (!url || url.length === 0) { |
|
||||
throw Error('"url" is a required parameter') |
|
||||
} |
|
||||
|
|
||||
const urlEncode = (params: any = {}) => { |
|
||||
const result :string[] = [] |
|
||||
for (const k in params) { |
|
||||
if (!params[k]) continue |
|
||||
result.push(k + '=' + params[k]) |
|
||||
} |
|
||||
|
|
||||
return result.join('&') |
|
||||
} |
|
||||
// const storage = JSON.parse(uni.getStorageSync('LX_user'))
|
|
||||
// const token = storage?.userInfo?.token
|
|
||||
// if(!token) {
|
|
||||
// url = 'pages/login/loginXcx'
|
|
||||
// mode = 'navigateTo'
|
|
||||
// }
|
|
||||
const queryStr = !isEmpty(params) ? '?' + urlEncode(params) : '' |
|
||||
const obj = { url: `/${url}${queryStr}` } |
|
||||
// console.log('obj', obj)
|
|
||||
switch (mode) { |
|
||||
case 'navigateTo': |
|
||||
uni.navigateTo(obj) |
|
||||
break |
|
||||
case 'redirectTo': |
|
||||
uni.redirectTo(obj) |
|
||||
break |
|
||||
case 'reLaunch': |
|
||||
uni.reLaunch(obj) |
|
||||
break |
|
||||
case 'switchTab': |
|
||||
uni.switchTab(obj) |
|
||||
break |
|
||||
default: |
|
||||
throw Error(`${mode} does not exist`) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 判断是否为空对象 |
|
||||
* @author liux |
|
||||
* @date 2023-08-15 14:17 |
|
||||
* @license MIT |
|
||||
* @param {*} object 源对象 |
|
||||
* @returns { boolean } |
|
||||
*/ |
|
||||
export const isEmptyObject = (object: any): boolean => { |
|
||||
return Object.keys(object).length === 0 |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 判断是否为对象 |
|
||||
* @author liux |
|
||||
* @date 2023-08-15 14:17 |
|
||||
* @license MIT |
|
||||
* @param {*} object 源对象 |
|
||||
* @returns { boolean } |
|
||||
*/ |
|
||||
export const isObject = (object: any): boolean => { |
|
||||
return Object.prototype.toString.call(object) === '[object Object]' |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 判断是否为数组 |
|
||||
* @author liux |
|
||||
* @license MIT |
|
||||
* @param {*} object 源对象 |
|
||||
* @returns { boolean } |
|
||||
*/ |
|
||||
export const isArray = (object: any): boolean => { |
|
||||
return Object.prototype.toString.call(object) === '[object Array]' |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 判断是否为空 |
|
||||
* @author liux |
|
||||
* @license MIT |
|
||||
* @param {*} value 源对象 |
|
||||
* @returns { boolean } |
|
||||
*/ |
|
||||
export const isEmpty = (value: any): boolean => { |
|
||||
if (isArray(value)) { |
|
||||
return value.length === 0 |
|
||||
} |
|
||||
if (isObject(value)) { |
|
||||
return isEmptyObject(value) |
|
||||
} |
|
||||
return !value |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 格式化时间戳(多格式) |
|
||||
* @author liux |
|
||||
* @license MIT |
|
||||
* @param { number } time 长度为 10 | 13 的时间戳 |
|
||||
* @param { string } [format=yyyy-MM-dd] format 转换格式 |
|
||||
* @example |
|
||||
* formatTime(1691744378556, 'yyyy-MM-dd HH:mm:ss') |
|
||||
* @returns { string } |
|
||||
*/ |
|
||||
|
|
||||
export const formatTime = (time: number, format: string = 'yyyy-MM-dd HH:mm:ss'): string => { |
|
||||
const len = time.toString().trim().length |
|
||||
if (len !== 10 && len !== 13) { |
|
||||
throw Error('"time" is a error parameter') |
|
||||
} |
|
||||
|
|
||||
time = len !== 13 ? time * 1000 : time |
|
||||
|
|
||||
if (!time) return '' |
|
||||
const date = new Date(time) |
|
||||
const M = (date.getMonth() + 1).toString() |
|
||||
const d = date.getDate().toString() |
|
||||
const H = date.getHours().toString() |
|
||||
const m = date.getMinutes().toString() |
|
||||
const s = date.getSeconds().toString() |
|
||||
const timeObject: { |
|
||||
[n: string]: string |
|
||||
} = { |
|
||||
yyyy: date.getFullYear().toString(), |
|
||||
MM: M.padStart(2, '0'), |
|
||||
dd: d.padStart(2, '0'), |
|
||||
HH: H.padStart(2, '0'), |
|
||||
mm: m.padStart(2, '0'), |
|
||||
ss: s.padStart(2, '0'), |
|
||||
M: M, |
|
||||
d: d, |
|
||||
H: H, |
|
||||
m: m, |
|
||||
s: s |
|
||||
} |
|
||||
const reg = new RegExp(Object.keys(timeObject).join('|'), 'g') |
|
||||
const res = format.replace(reg, (k) => { |
|
||||
return timeObject[k] |
|
||||
}) |
|
||||
return res |
|
||||
} |
|
||||
|
|
||||
// 判断当前时间是否在一个时间区间内
|
|
||||
export const isTimeIn = (start: string, end: string) => { |
|
||||
// 获取当前时间
|
|
||||
const currentTime = new Date() |
|
||||
const startArr = start.split(':').map(Number) |
|
||||
// 设置开始时间为10:00
|
|
||||
const startTime = new Date() |
|
||||
startTime.setHours(startArr[0], startArr[1]) |
|
||||
|
|
||||
// 设置结束时间为20:00
|
|
||||
const endArr = end.split(':').map(Number) |
|
||||
const endTime = new Date() |
|
||||
endTime.setHours(endArr[0], endArr[1]) |
|
||||
|
|
||||
// 检查当前时间是否在10:00到20:00之间
|
|
||||
if (currentTime >= startTime && currentTime <= endTime) { |
|
||||
// console.log('当前时间在之间')
|
|
||||
} else { |
|
||||
// console.log('当前时间不在之间')
|
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 防抖函数 |
|
||||
* @author liux |
|
||||
* @license MIT |
|
||||
* @param {function} fn |
|
||||
* @param {umber} [wait=1000] wait |
|
||||
* @returns { void } |
|
||||
*/ |
|
||||
export const debounce = <T extends (...args: any[]) => any>(fn: T, wait: number = 1000): ((...args: Parameters<T>) => void) => { |
|
||||
let timer: any |
|
||||
|
|
||||
return function (this: any, ...args: Parameters<T>) { |
|
||||
if (timer) clearTimeout(timer) |
|
||||
|
|
||||
timer = setTimeout(() => { |
|
||||
fn.apply(this, args) |
|
||||
}, wait) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 节流函数 |
|
||||
* @author liux |
|
||||
* @date 2023-08-15 14:17 |
|
||||
* @license MIT |
|
||||
* @param { function } fn |
|
||||
* @param { number } [wait=1000] wait |
|
||||
*/ |
|
||||
export const throttle = <T extends (...args: any[]) => any>(fn: T, wait: number = 1000) => { |
|
||||
let timer: number = Date.now() |
|
||||
return function (this: any, ...args: Parameters<T>) { |
|
||||
if (Date.now() - timer >= wait) { |
|
||||
fn.apply(this, args) |
|
||||
timer = Date.now() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 保存图片到本地 |
|
||||
* @author liux |
|
||||
* @param { string } url 需要下载的图片 |
|
||||
* @example |
|
||||
* saveImgData('/upload/images/img.png') |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const saveImgData = debounce((url: string) => { |
|
||||
uni.showLoading({ title: '图片保存中...', mask: true }) |
|
||||
// 判断图片地址是否有http
|
|
||||
if (url.indexOf('http') === -1) { |
|
||||
url = import.meta.env.VITE_APP_BASE_URL + url |
|
||||
} |
|
||||
uni.downloadFile({ |
|
||||
url, |
|
||||
success: (res: any) => { |
|
||||
if (res.statusCode === 200) { |
|
||||
uni.saveImageToPhotosAlbum({ |
|
||||
filePath: res.tempFilePath, |
|
||||
success: () => { |
|
||||
uni.showToast({ |
|
||||
title: '保存成功~', |
|
||||
icon: 'none', |
|
||||
duration: 2000 |
|
||||
}) |
|
||||
}, |
|
||||
fail: () => { |
|
||||
uni.showToast({ |
|
||||
title: '保存失败~', |
|
||||
icon: 'none', |
|
||||
duration: 2000 |
|
||||
}) |
|
||||
}, |
|
||||
complete: () => { |
|
||||
uni.hideLoading() |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
}) |
|
||||
|
|
||||
/** |
|
||||
* 设置剪贴板 |
|
||||
* @author liux |
|
||||
* @param { string } data 需要复制的内容 |
|
||||
* @example |
|
||||
* setClipboardData('123456') |
|
||||
* @returns |
|
||||
*/ |
|
||||
export const setClipboardData = (data: string) => { |
|
||||
uni.setClipboardData({ |
|
||||
data: data, |
|
||||
success: () => { |
|
||||
uni.showToast({ |
|
||||
title: '复制成功', |
|
||||
icon: 'none', |
|
||||
duration: 2000 |
|
||||
}) |
|
||||
} |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
export default { |
|
||||
goToPage, |
|
||||
formatTime, |
|
||||
debounce, |
|
||||
throttle, |
|
||||
saveImgData, |
|
||||
setClipboardData |
|
||||
} |
|
||||
@ -1,133 +0,0 @@ |
|||||
<template> |
|
||||
<view class="zcks-card"> |
|
||||
<view class="craditem" v-for="(item,index) in newCheckOptions" :key="index" :class="{'active': item.selected}" |
|
||||
:style="{ '--color': activeColor }" @click="selectData(index,item)"> |
|
||||
{{item.sku_name}} |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
props: { |
|
||||
//选项数据 |
|
||||
checkOptions: { |
|
||||
type: Array, |
|
||||
default () { |
|
||||
return [] |
|
||||
} |
|
||||
}, |
|
||||
//选择类型(单选:single,默认复选) |
|
||||
checkType: { |
|
||||
type: String, |
|
||||
default: '' |
|
||||
}, |
|
||||
//复选时最大可选数量(类型为单选的时不生效) |
|
||||
maxNum: { |
|
||||
type: Number, |
|
||||
}, |
|
||||
//主题色 |
|
||||
activeColor: { |
|
||||
type: String, |
|
||||
default: '#0A4B9D' |
|
||||
} |
|
||||
}, |
|
||||
watch: { |
|
||||
checkOptions: { |
|
||||
deep: true, |
|
||||
immediate: true, |
|
||||
handler(parentArry) { |
|
||||
this.newCheckOptions = parentArry |
|
||||
}, |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
newCheckOptions: [] |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
selectData(index, item) { |
|
||||
if (this.checkType == 'single') { //单选 |
|
||||
this.newCheckOptions.forEach(mess => { |
|
||||
mess.selected = false |
|
||||
}) |
|
||||
this.$set(item, 'selected', true) |
|
||||
} else { |
|
||||
let chooseData = this.newCheckOptions.filter(mes => mes.selected) |
|
||||
if (this.maxNum && !item.selected && chooseData.length >= this.maxNum) { |
|
||||
uni.showToast({ |
|
||||
title: '最多可选' + this.maxNum + '项', |
|
||||
icon: 'none' |
|
||||
}) |
|
||||
return |
|
||||
} |
|
||||
this.$set(item, 'selected', item.selected ? false : true) |
|
||||
} |
|
||||
this.newCheckOptions = JSON.parse(JSON.stringify(this.newCheckOptions)) |
|
||||
let chooseOnData = this.newCheckOptions.filter(mes => mes.selected) |
|
||||
this.$emit("checkChange", chooseOnData) |
|
||||
}, |
|
||||
//重置 |
|
||||
reset() { |
|
||||
this.newCheckOptions.forEach(mess => { |
|
||||
mess.selected = false |
|
||||
}) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style scoped> |
|
||||
.zcks-card { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: flex-start; |
|
||||
flex-wrap: wrap; |
|
||||
} |
|
||||
|
|
||||
.craditem { |
|
||||
padding: 8rpx 24rpx; |
|
||||
margin-right: 24rpx; |
|
||||
margin-bottom: 16rpx; |
|
||||
background: #FFFFFF; |
|
||||
border-radius: 4rpx; |
|
||||
border: 2rpx solid #999999; |
|
||||
font-size: 30rpx; |
|
||||
font-weight: 400; |
|
||||
color: #333333; |
|
||||
line-height: 48rpx; |
|
||||
text-align: left; |
|
||||
} |
|
||||
|
|
||||
.active { |
|
||||
border: 2rpx solid var(--color); |
|
||||
color: var(--color); |
|
||||
position: relative; |
|
||||
} |
|
||||
|
|
||||
.active::after { |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
top: 0; |
|
||||
right: 0; |
|
||||
width: 0; |
|
||||
height: 0; |
|
||||
border-top: 42rpx solid var(--color); |
|
||||
border-left: 42rpx solid transparent; |
|
||||
} |
|
||||
|
|
||||
.active::before { |
|
||||
width: 8rpx; |
|
||||
height: 12rpx; |
|
||||
border-color: #FFFFFF; |
|
||||
border-style: solid; |
|
||||
border-width: 0 1rpx 2rpx 0; |
|
||||
content: ""; |
|
||||
position: absolute; |
|
||||
right: 8rpx; |
|
||||
top: 2rpx; |
|
||||
z-index: 3; |
|
||||
transform: rotate(45deg); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,249 +0,0 @@ |
|||||
<script lang="ts" setup> |
|
||||
/* |
|
||||
* @description: 头部组件 |
|
||||
* @fileName: Header.vue |
|
||||
* @params |
|
||||
* @author: lxx |
|
||||
* @date: 2023-07-16 09:32:09 |
|
||||
* @version: V1.0.2 |
|
||||
*/ |
|
||||
import { goToPage } from '../libs/util' |
|
||||
import { type CSSProperties, computed, ref, watchEffect } from 'vue' |
|
||||
|
|
||||
type headerInt = { |
|
||||
title: string |
|
||||
// 头部高度 默认为44px (微信小程序不可用) |
|
||||
headerHeight?: number |
|
||||
// 是否显示左侧内容 |
|
||||
leftIconShow?: boolean |
|
||||
// 样式部分 |
|
||||
backgroundColor?: string |
|
||||
backgroundColor2?: string |
|
||||
textColor?: string |
|
||||
textFontSize?: number |
|
||||
// 是否需要生成和头部高度相同的盒子 |
|
||||
isShowHeaderBox?: boolean |
|
||||
positionState?: string |
|
||||
isShowShadow?: boolean |
|
||||
isBlackIcon?: boolean |
|
||||
// 头部没有右侧盒子,true:左中右结构 false:左中结构(小程序可以为左中右结构但是没有右侧盒子) |
|
||||
isHaveRightBox?: boolean |
|
||||
} |
|
||||
|
|
||||
const props = withDefaults(defineProps<headerInt>(), { |
|
||||
// 头部高度 默认为44px (微信小程序不可用) |
|
||||
headerHeight: 44, |
|
||||
// 是否显示左侧内容 |
|
||||
leftIconShow: true, |
|
||||
// 样式部分 |
|
||||
backgroundColor: '#ffffff', //linear-gradient(90deg, rgba(10, 207, 254, 1) 0%, rgba(74, 92, 255, 1) 100%) |
|
||||
backgroundColor2: '#ffffff', |
|
||||
textColor: '#000', |
|
||||
textFontSize: 34, |
|
||||
title: '标题', |
|
||||
// 是否需要生成和头部高度相同的盒子 |
|
||||
isShowHeaderBox: true, |
|
||||
positionState: 'fixed', |
|
||||
isShowShadow: false, |
|
||||
isBlackIcon: true, // 是否为黑色图标 |
|
||||
isHaveRightBox: true |
|
||||
}) |
|
||||
|
|
||||
let { statusBarHeight } = uni.getSystemInfoSync() |
|
||||
// #ifdef MP-WEIXIN |
|
||||
// 胶囊状态 |
|
||||
let menuButton = uni.getMenuButtonBoundingClientRect() |
|
||||
// 微信头部宽度 |
|
||||
let wxHeaderWidth = menuButton.left - 10 |
|
||||
// 上边距 |
|
||||
statusBarHeight = menuButton.top |
|
||||
// #endif |
|
||||
|
|
||||
// padding的高度(防止头部塌陷) |
|
||||
const fillBoxHeight = ref(statusBarHeight + 3) |
|
||||
|
|
||||
// 设置header的高度 |
|
||||
const headerHeightRef = ref(0) |
|
||||
watchEffect(() => { |
|
||||
headerHeightRef.value = props.headerHeight |
|
||||
// #ifdef MP-WEIXIN |
|
||||
// 中间高度 |
|
||||
headerHeightRef.value = menuButton.height |
|
||||
// #endif |
|
||||
}) |
|
||||
// console.log('statusBarHeight', statusBarHeight) |
|
||||
|
|
||||
const style = computed(() => { |
|
||||
return { |
|
||||
boxShadow: props.isShowShadow ? '0 0 8rpx -3rpx #333' : '0 0 0 0 #333', |
|
||||
background: props.backgroundColor, |
|
||||
color: props.textColor, |
|
||||
position: props.positionState |
|
||||
} as CSSProperties |
|
||||
}) |
|
||||
// 返回上一页(如没有页面返回首页) |
|
||||
const goBack = () => { |
|
||||
if (getCurrentPages().length <= 1) { |
|
||||
goToPage({ |
|
||||
url: 'pages/index/index', |
|
||||
mode: 'redirectTo' |
|
||||
}) |
|
||||
} else { |
|
||||
uni.navigateBack() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const backIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACMklEQVR4nO2av0uVURjHPyiEYgkuoVC4ODSK2pRDYFOENOQP6A+IEgknkWgKgqTEP6AaHIKyhqhGiSgVpKwGBweLBMHZcjAK47xcXrxxn6el5/pwzvnAme5wv5/ve+/hPO/7kslkMplMxjsjwCdgB7iV2tW6Aez/tW46yFUXpmvIh/U6AXfuCvJhnXOQz5R7ivz1iL0LZhX5Sw7ymTIviG8DpyP2pg14Kch/BjodZDSjHdgQ5D8CrZF6F3QD3wT5VeCog4xm9ADfBfn3scv3KvJhL2hxkNGMsJv/EOQfRepcchbYFeQnnWQ046JywLkSqXPJlCJ/2UlGM7Rz/WikziX3BfFfwLCTjGY8FuR/Av2ROpdIQ004159yktGMZ4L8Yuzn+mZgQZB/BTQ6yGhGOLevCPIvInUu6QK+CPLPnWQ05Z0gPxuxcxXSIWfAUUZT5oQCfgPXIvau4onyS5hwlNOUB0oJcxF7V6ENPuFofMRRVjNuKyW8SaWEIaWEt0CTg4zmDCq3v5ZSKUG7AboMdDjIaE6fUsJX4ETk/gU9lddbapWwncLzfiqPwTaVzfGCg4zmdCiTYxJ3iPnHo/CwrjrIWBeeKiWMJeBfoM0P4w7y1YUZpYQ7CfgXaEPUtIN8dUF6KXK/cqu9IYEOincApRIWU5kfxpUS1oDjDjKacx7YE0rYSGWI6lXmh4f/60s8bywfKkPUVo3Pjh1CnkPjJLB+4OqHv8aZlArIZDKZTMYC4A8EQ0uQY7/3uAAAAABJRU5ErkJggg==' |
|
||||
const backIconW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAACjElEQVR4nO2azatNURiH364S+SgTuUUmBoa6GDEwuCNJBr7KHyAkGUkyUsoN3T8AA0r5GugyUZK4lHwODAwQpYwvBqQeve4+deK8a5+zz9q3d6+9nnonp7PXWb/n7L1aH1symUwmk8lUBpiL2gO8BmaAU/p7bpiD8Cf4n5NtETDRI7zywEH0WWoMf9YIr4x7yP6XmsKfC4Q/kvoYMBkIv7PzPTdEDn/DCP4V2Nj93dQELAPuGOHfAKv/vcYNEcKvAN4b4V8BS3tdl4qAdcAnI/xLYLF1rRuGCD8GfDPCPw+FT0HA+kB4HQsWlbXhhgrhdTT/boS/2m87TRWwBfhhhD82SFtuGKDTO4zgyv5B76SmCTgeCL+vyjjihj46G5rX7604iDZGwAUj+G9gd9XwTRFwzQj/C9g8TPgmCLAWNTqvXztseO8Cbhnhp615fSoCFgL3jfB3gXmxwnsUoPP2Z0b4qZjBPQpYA3wwwt+uI7w3AY+N8JN1hY8pYCRCG5uMz6citF07MQRcMT6/JyIHHWWth+KWvG48BsrR1MeATl0MSLjcBgFSsvDRqfH81AVonQ5IeBhLghuMDu4KSHgELEhdgNb2wPbXk2EluKGko6EN0KfAaOoCtDYEJHwEVqYuQIpDkBlDgh58jqcuQIpjsM+BwXFb6gKkeOatlSOD7BC7ocLzGzoKVw6kLqBTNwMSDrVBgJSsHw63QYDW+YCEM20QICWLqIk2CJDAS5EUW+0jqQuQ4h1Ai+nu9YMbIguQYvCzeAssT12A1lbgpyFB3ygbdRB9lpoESPEekbV+uBSr/zF2hevihYiMiciXHu0vcdPLGu+ATq0C3nX9+/poWGcRmUwmk8lk+kRE/gCfWLdyj0KPNgAAAABJRU5ErkJggg==' |
|
||||
</script> |
|
||||
|
|
||||
<template> |
|
||||
<!-- #ifndef MP-TOUTIAO --> |
|
||||
<view class="header_box"> |
|
||||
<view class="header_main" :style="style"> |
|
||||
<view class="status_bar" :style="{ height: statusBarHeight + 'px' }"></view> |
|
||||
<!-- 标准的左中右结构 --> |
|
||||
<view v-if="isHaveRightBox" class="header flex-center-between" :style="{ height: headerHeightRef + 'px' }"> |
|
||||
<view class="header_left flex-center-between"> |
|
||||
<slot name="left"> |
|
||||
<view v-if="leftIconShow" class="icon flex" @click="goBack"> |
|
||||
<image :src="isBlackIcon ? backIcon : backIconW" mode="widthFix"></image> |
|
||||
</view> |
|
||||
</slot> |
|
||||
</view> |
|
||||
<view class="header_center"> |
|
||||
<slot> |
|
||||
<view class="title" :style="{ fontSize: textFontSize + 'rpx' }"> |
|
||||
{{ title }} |
|
||||
</view> |
|
||||
</slot> |
|
||||
</view> |
|
||||
<view class="header_right flex"> |
|
||||
<!-- #ifndef MP-WEIXIN --> |
|
||||
<slot name="right"></slot> |
|
||||
<!-- #endif --> |
|
||||
</view> |
|
||||
</view> |
|
||||
<!-- 左右结构 --> |
|
||||
<view v-else class="wx_header flex" |
|
||||
:style="{ height: headerHeightRef + 'px', width: wxHeaderWidth + 'px' }"> |
|
||||
<view class="wx_header_left flex"> |
|
||||
<slot name="left"> |
|
||||
<view class="icon flex" @click="goBack" v-if="leftIconShow"> |
|
||||
<image :src="isBlackIcon ? backIcon : backIconW" mode="widthFix"></image> |
|
||||
</view> |
|
||||
</slot> |
|
||||
</view> |
|
||||
<view class="wx_header_txt flex"> |
|
||||
<slot name="center"> |
|
||||
<view class="title" :style="{ fontSize: textFontSize + 'rpx' }"> |
|
||||
{{ title }} |
|
||||
</view> |
|
||||
</slot> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<!-- 填充头部防止塌陷 新加(v-if="isShowHeaderBox") --> |
|
||||
<view class="status_bar" v-if="isShowHeaderBox" :style="{ height: fillBoxHeight + 'px' }"></view> |
|
||||
<!-- #ifdef MP-WEIXIN --> |
|
||||
<view v-if="isShowHeaderBox" :style="{ height: headerHeightRef + 4 + 'px', background: backgroundColor2 }"> |
|
||||
</view> |
|
||||
<!-- #endif --> |
|
||||
<!-- 待测试 --> |
|
||||
<!-- #ifndef MP-WEIXIN --> |
|
||||
<view v-if="isShowHeaderBox" :style="{ height: headerHeightRef + 'px', background: backgroundColor2 }"></view> |
|
||||
<!-- #endif --> |
|
||||
</view> |
|
||||
<!-- #endif --> |
|
||||
</template> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.header_box { |
|
||||
// padding: 0 20rpx 5rpx; |
|
||||
// background-color: #fff; |
|
||||
} |
|
||||
|
|
||||
.header_main { |
|
||||
width: 100%; |
|
||||
z-index: 9999; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
/* #ifdef MP-WEIXIN */ |
|
||||
padding: 0 20rpx 15rpx; |
|
||||
/* #endif */ |
|
||||
/* #ifndef MP-WEIXIN */ |
|
||||
padding: 5rpx 20rpx; |
|
||||
/* #endif */ |
|
||||
box-sizing: border-box; |
|
||||
|
|
||||
.img { |
|
||||
width: 48rpx; |
|
||||
height: 48rpx; |
|
||||
} |
|
||||
|
|
||||
.header { |
|
||||
// padding: 0 16rpx; |
|
||||
box-sizing: border-box; |
|
||||
|
|
||||
.header_left { |
|
||||
width: 20%; |
|
||||
|
|
||||
.icon { |
|
||||
width: 48rpx; |
|
||||
} |
|
||||
|
|
||||
.left_txt { |
|
||||
font-size: 22rpx; |
|
||||
line-height: 22rpx; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.header_center { |
|
||||
width: 60%; |
|
||||
text-align: center; |
|
||||
font-size: 28rpx; |
|
||||
|
|
||||
.title { |
|
||||
overflow: hidden; |
|
||||
text-overflow: ellipsis; |
|
||||
white-space: nowrap; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.header_right { |
|
||||
width: 20%; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.wx_header { |
|
||||
.wx_header_left { |
|
||||
height: 100%; |
|
||||
|
|
||||
.icon { |
|
||||
width: 48rpx; |
|
||||
|
|
||||
image { |
|
||||
vertical-align: middle; |
|
||||
width: 100%; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.wx_header_txt { |
|
||||
flex: 1; |
|
||||
height: 100%; |
|
||||
padding-left: 26rpx; |
|
||||
|
|
||||
.title { |
|
||||
width: 100%; |
|
||||
line-height: 1; |
|
||||
overflow: hidden; |
|
||||
text-overflow: ellipsis; |
|
||||
white-space: nowrap; |
|
||||
font-size: 28rpx; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
../../libs/util |
|
||||
@ -1,35 +0,0 @@ |
|||||
<template> |
|
||||
<image :src="imgUrl" :style="{ 'width': width, 'height': height, 'border-radius': round }" :mode="mode" /> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { computed } from 'vue'; |
|
||||
|
|
||||
interface propInt { |
|
||||
imgUrl: string |
|
||||
mode: string |
|
||||
width: string |
|
||||
height: string |
|
||||
round: string |
|
||||
} |
|
||||
|
|
||||
const props = withDefaults(defineProps<propInt>(), { |
|
||||
// 图片路径 |
|
||||
src: '', |
|
||||
// 图片模式 |
|
||||
mode: '', |
|
||||
// 图片宽 |
|
||||
width: '100%', |
|
||||
// 图片高 |
|
||||
height: '100%', |
|
||||
// 圆角 |
|
||||
round: '' |
|
||||
}) |
|
||||
|
|
||||
const imgUrl = computed(() => { |
|
||||
return import.meta.env.VITE_IMG_DOMAIN + props.src |
|
||||
}) |
|
||||
|
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped></style> |
|
||||
File diff suppressed because one or more lines are too long
@ -1,102 +0,0 @@ |
|||||
<script setup lang="ts"> |
|
||||
/* |
|
||||
* @description: 分页组件 |
|
||||
* @fileName: List.vue |
|
||||
* @params {Function} api : 数据请求的接口API |
|
||||
* @params {Function} afterLoadData : 数据请求完毕前置处理方法 |
|
||||
* @params {object: any} options : 数据请求的额外参数 |
|
||||
* @params {'default' | 'scrollView'} listType : scrollView为scroll-view包裹的分页 |
|
||||
* @ref setListParams {Function} : 使用==>ref.value.setListParams(obj, isClear) obj:请求额外的参数 isClear是否清空请求参数 |
|
||||
* @author: lxx |
|
||||
* @date: 2023-07-28 11:36:23 |
|
||||
* @update: 2023-10-13 10:34:03 |
|
||||
* @version: V1.0.1 |
|
||||
*/ |
|
||||
import { LoadData } from '../libs/hooks/useListLoadClass' |
|
||||
import { toRefs, ref } from 'vue'; |
|
||||
import lxListState from '../lx-list-state/lx-list-state.vue' |
|
||||
interface listPropsInt { |
|
||||
api: Function |
|
||||
afterLoadData?: Function |
|
||||
options?: any |
|
||||
listType?: 'default' | 'scrollView' |
|
||||
} |
|
||||
|
|
||||
// 接收传值 |
|
||||
// 3.2.x defineProps泛型类型参数仅限于类型文字或对本地接口的引用 |
|
||||
const props = withDefaults(defineProps<listPropsInt>(), { |
|
||||
api: () => ({}), |
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function |
|
||||
options: {}, |
|
||||
listType: 'default' |
|
||||
}) |
|
||||
let { options, api, afterLoadData } = toRefs(props) |
|
||||
// console.log('props', props.options, options.value) |
|
||||
|
|
||||
// 分页相关 |
|
||||
let { list, isLoading, isEmpty, isNoData, setParams, LoadMore } = LoadData({ |
|
||||
api: api.value, |
|
||||
afterLoadData: afterLoadData?.value, |
|
||||
options: options.value |
|
||||
}) |
|
||||
// 搜索相关 |
|
||||
// const inputTxt = ref('') |
|
||||
// const inputChange = debounce(() => { |
|
||||
// console.log('input change') |
|
||||
// setParams({ search: inputTxt.value }) |
|
||||
// }) |
|
||||
|
|
||||
// 用于父组件设置额外的参数(选项卡切换的时候使用)--> isClear true 清空列表需测试 |
|
||||
const setListParams = (obj: any, isClear = true) => { |
|
||||
const param = ref<{ |
|
||||
search?: string |
|
||||
[key: string]: any |
|
||||
}>({}) |
|
||||
// if (props.isNeedSearch) { |
|
||||
// param.value.search = inputTxt.value |
|
||||
// } |
|
||||
param.value = { ...obj } |
|
||||
setParams({ ...param.value }, isClear) |
|
||||
} |
|
||||
defineExpose({ |
|
||||
list, |
|
||||
setListParams, |
|
||||
LoadMore |
|
||||
}) |
|
||||
// 页面滚动相关 |
|
||||
const scrollTop = ref(0) |
|
||||
const scroll = (e: any) => { |
|
||||
scrollTop.value = e.detail.scrollTop |
|
||||
} |
|
||||
|
|
||||
const emit = defineEmits(['scrollTolower']) |
|
||||
const scrolltolower = () => { |
|
||||
console.log('触底啦!') |
|
||||
LoadMore() |
|
||||
emit('scrollTolower') |
|
||||
} |
|
||||
</script> |
|
||||
<template> |
|
||||
<template v-if="listType == 'default'"> |
|
||||
<view class="lxx_list_box"> |
|
||||
<view class="lxx_list_box_content"> |
|
||||
<template v-for="(item, index) in list" :key="index"> |
|
||||
<slot v-bind:item="item" v-bind:index="index"></slot> |
|
||||
</template> |
|
||||
</view> |
|
||||
<lxListState :is-empty="isEmpty" :is-loading="isLoading" :is-no-data="isNoData"></lxListState> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<template v-else> |
|
||||
<scroll-view scroll-y="true" class="scroll-Y" @scroll="scroll" @scrolltolower="scrolltolower"> |
|
||||
<view class="lxx_list_box"> |
|
||||
<view v-for="(item, index) in list" :key="index"> |
|
||||
<slot v-bind:item="item" v-bind:index="index"></slot> |
|
||||
</view> |
|
||||
</view> |
|
||||
<lxListState :is-empty="isEmpty" :is-loading="isLoading" :is-no-data="isNoData"></lxListState> |
|
||||
</scroll-view> |
|
||||
</template> |
|
||||
</template> |
|
||||
<style lang="scss" scoped></style> |
|
||||
@ -1,66 +0,0 @@ |
|||||
// 小程序无法在hook中使用页面级别生命周期,需单独传入: https://ask.dcloud.net.cn/question/161173
|
|
||||
// import { onPageScroll, onReachBottom, onPullDownRefresh} from '@dcloudio/uni-app';
|
|
||||
|
|
||||
/** |
|
||||
* 初始化mescroll, 相当于vue2的mescroll-mixins.js文件 (mescroll-body 和 mescroll-uni 通用) |
|
||||
* mescroll-body需传入onPageScroll, onReachBottom |
|
||||
* mescroll-uni无需传onPageScroll, onReachBottom |
|
||||
* 当down.native为true时,需传入onPullDownRefresh |
|
||||
*/ |
|
||||
function useMescroll(onPageScroll, onReachBottom, onPullDownRefresh){ |
|
||||
// mescroll实例对象
|
|
||||
let mescroll = null; |
|
||||
|
|
||||
// mescroll组件初始化的回调,可获取到mescroll对象
|
|
||||
const mescrollInit = (e)=> { |
|
||||
mescroll = e; |
|
||||
} |
|
||||
|
|
||||
// 获取mescroll对象, mescrollInit执行之后会有值, 生命周期created中会有值
|
|
||||
const getMescroll = ()=>{ |
|
||||
return mescroll |
|
||||
} |
|
||||
|
|
||||
// 下拉刷新的回调 (mixin默认resetUpScroll)
|
|
||||
const downCallback = ()=> { |
|
||||
if(mescroll.optUp.use){ |
|
||||
mescroll.resetUpScroll() |
|
||||
}else{ |
|
||||
setTimeout(()=>{ |
|
||||
mescroll.endSuccess(); |
|
||||
}, 500) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 上拉加载的回调
|
|
||||
const upCallback = ()=> { |
|
||||
// mixin默认延时500自动结束加载
|
|
||||
setTimeout(()=>{ |
|
||||
mescroll.endErr(); |
|
||||
}, 500) |
|
||||
} |
|
||||
|
|
||||
// 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例)
|
|
||||
onPullDownRefresh && onPullDownRefresh(() => { |
|
||||
mescroll && mescroll.onPullDownRefresh(); |
|
||||
}) |
|
||||
|
|
||||
// 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效)
|
|
||||
onPageScroll && onPageScroll(e=>{ |
|
||||
mescroll && mescroll.onPageScroll(e); |
|
||||
}) |
|
||||
|
|
||||
// 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效)
|
|
||||
onReachBottom && onReachBottom(()=>{ |
|
||||
mescroll && mescroll.onReachBottom(); |
|
||||
}) |
|
||||
|
|
||||
return { |
|
||||
getMescroll, |
|
||||
mescrollInit, |
|
||||
downCallback, |
|
||||
upCallback |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
export default useMescroll |
|
||||
@ -1,56 +0,0 @@ |
|||||
import { ref } from 'vue'; |
|
||||
|
|
||||
// 小程序无法在hook中使用页面级别生命周期,需单独传入: https://ask.dcloud.net.cn/question/161173
|
|
||||
// import { onPageScroll, onReachBottom, onPullDownRefresh} from '@dcloudio/uni-app';
|
|
||||
|
|
||||
/** |
|
||||
* mescroll-body写在子组件时,需通过useMescrollComp补充子组件缺少的生命周期, 相当于vue2的mescroll-comp.js文件 |
|
||||
* 必须传入onPageScroll, onReachBottom |
|
||||
* 当down.native为true时,需传入onPullDownRefresh |
|
||||
*/ |
|
||||
function useMescrollComp(onPageScroll, onReachBottom, onPullDownRefresh){ |
|
||||
// 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件
|
|
||||
onPageScroll(e=>{ |
|
||||
handlePageScroll(e) |
|
||||
}) |
|
||||
|
|
||||
onReachBottom(()=>{ |
|
||||
handleReachBottom() |
|
||||
}) |
|
||||
|
|
||||
// 当down的native: true时, 还需传递此方法进到子组件
|
|
||||
onPullDownRefresh && onPullDownRefresh(()=>{ |
|
||||
handlePullDownRefresh() |
|
||||
}) |
|
||||
|
|
||||
const mescrollItem = ref(null) |
|
||||
|
|
||||
const handlePageScroll = (e)=>{ |
|
||||
const mescroll = getMescroll() |
|
||||
mescroll && mescroll.onPageScroll(e); |
|
||||
} |
|
||||
|
|
||||
const handleReachBottom = ()=>{ |
|
||||
const mescroll = getMescroll() |
|
||||
mescroll && mescroll.onReachBottom(); |
|
||||
} |
|
||||
|
|
||||
const handlePullDownRefresh = ()=>{ |
|
||||
const mescroll = getMescroll() |
|
||||
mescroll && mescroll.onPullDownRefresh(); |
|
||||
} |
|
||||
|
|
||||
const getMescroll = ()=>{ |
|
||||
if(mescrollItem.value && mescrollItem.value.getMescroll){ |
|
||||
return mescrollItem.value.getMescroll() |
|
||||
} |
|
||||
return null |
|
||||
} |
|
||||
|
|
||||
return { |
|
||||
mescrollItem, |
|
||||
getMescroll |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
export default useMescrollComp |
|
||||
@ -1,69 +0,0 @@ |
|||||
import { ref } from 'vue'; |
|
||||
|
|
||||
// 小程序无法在hook中使用页面级别生命周期,需单独传入: https://ask.dcloud.net.cn/question/161173
|
|
||||
// import { onPageScroll, onReachBottom, onPullDownRefresh} from '@dcloudio/uni-app';
|
|
||||
|
|
||||
/** mescroll-more示例写在子组件时,需通过useMescrollMore补充子组件缺少的生命周期, 相当于vue2的mescroll-more.js文件 */ |
|
||||
function useMescrollMore(mescrollItems, onPageScroll, onReachBottom, onPullDownRefresh){ |
|
||||
// 当前tab下标
|
|
||||
const tabIndex = ref(0) |
|
||||
|
|
||||
// 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件
|
|
||||
onPageScroll && onPageScroll(e=>{ |
|
||||
handlePageScroll(e) |
|
||||
}) |
|
||||
|
|
||||
onReachBottom && onReachBottom(()=>{ |
|
||||
handleReachBottom() |
|
||||
}) |
|
||||
|
|
||||
// 当down的native: true时, 还需传递此方法进到子组件
|
|
||||
onPullDownRefresh && onPullDownRefresh(()=>{ |
|
||||
handlePullDownRefresh() |
|
||||
}) |
|
||||
|
|
||||
const handlePageScroll = (e)=>{ |
|
||||
let mescroll = getMescroll(tabIndex.value); |
|
||||
mescroll && mescroll.onPageScroll(e); |
|
||||
} |
|
||||
const handleReachBottom = ()=>{ |
|
||||
let mescroll = getMescroll(tabIndex.value); |
|
||||
mescroll && mescroll.onReachBottom(); |
|
||||
} |
|
||||
|
|
||||
const handlePullDownRefresh = ()=>{ |
|
||||
let mescroll = getMescroll(tabIndex.value); |
|
||||
mescroll && mescroll.onPullDownRefresh(); |
|
||||
} |
|
||||
|
|
||||
// 根据下标获取对应子组件的mescroll
|
|
||||
const getMescroll = (i)=>{ |
|
||||
if (mescrollItems && mescrollItems[i]) { |
|
||||
return mescrollItems[i].value.getMescroll() |
|
||||
} else{ |
|
||||
return null |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 切换tab,恢复滚动条位置
|
|
||||
const scrollToLastY = ()=>{ |
|
||||
let mescroll = getMescroll(tabIndex.value); |
|
||||
if(mescroll){ |
|
||||
// 恢复上次滚动条的位置
|
|
||||
let y = mescroll.getScrollTop() |
|
||||
mescroll.scrollTo(y, 0) |
|
||||
// 再次恢复上次滚动条的位置, 确保元素已渲染
|
|
||||
setTimeout(()=>{ |
|
||||
mescroll.scrollTo(y, 0) |
|
||||
},20) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return { |
|
||||
tabIndex, |
|
||||
getMescroll, |
|
||||
scrollToLastY |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
export default useMescrollMore |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue