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' |
|||
|
|||
# api请求地址 |
|||
VITE_APP_BASE_URL='http://shop.zeyan.wang/index.php/api/' |
|||
|
|||
# 图片服务器地址 |
|||
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' |
|||
ENV='development' |
|||
# base api |
|||
VITE_APP_BASE_URL = 'https://evote.truescloud.com' |
|||
VITE_APP_BASE_PRE = '/dev-api' |
|||
VITE_APP_BASE_NAME = 'POS' |
|||
|
|||
@ -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 |
|||
logs |
|||
*.log |
|||
.DS_Store |
|||
/node_modules |
|||
/dist |
|||
|
|||
# local env files |
|||
.env.local |
|||
.env.*.local |
|||
|
|||
# Log files |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
lerna-debug.log* |
|||
|
|||
node_modules |
|||
.DS_Store |
|||
dist |
|||
*.local |
|||
|
|||
# Editor directories and files |
|||
.project |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
.hbuilderx |
|||
*.sw* |
|||
|
|||
/unpackage |
|||
.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) |
|||
} |
|||
@ -1,20 +1,23 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="zh-cn"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<script> |
|||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || |
|||
CSS.supports('top: constant(a)')) |
|||
document.write( |
|||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + |
|||
(coverSupport ? ', viewport-fit=cover' : '') + '" />') |
|||
</script> |
|||
<title></title> |
|||
<!--preload-links--> |
|||
<!--app-context--> |
|||
</head> |
|||
<body> |
|||
<div id="app"><!--app-html--></div> |
|||
<script type="module" src="/src/main.js"></script> |
|||
</body> |
|||
</html> |
|||
<html> |
|||
|
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<script> |
|||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || |
|||
CSS.supports('top: constant(a)')) |
|||
document.write( |
|||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + |
|||
(coverSupport ? ', viewport-fit=cover' : '') + '" />') |
|||
</script> |
|||
<title></title> |
|||
<!--preload-links--> |
|||
<!--app-context--> |
|||
</head> |
|||
|
|||
<body> |
|||
<view id="app"><!--app-html--></view> |
|||
<script type="module" src="/src/main.ts"></script> |
|||
</body> |
|||
|
|||
</html> |
|||
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"> |
|||
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app' |
|||
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) => { |
|||
|
|||
// // 添加初始化拦截器 |
|||
// 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(() => { |
|||
}) |
|||
|
|||
onHide(() => { |
|||
}) |
|||
// import routingIntercept from '@/permission' |
|||
|
|||
onLaunch(() => { |
|||
// routingIntercept() |
|||
}) |
|||
onShow(() => { |
|||
console.log('App Show') |
|||
}) |
|||
onHide(() => { |
|||
console.log('App Hide') |
|||
}) |
|||
// 全局变量 |
|||
// provide('globalObj', <globalObjInt>{ |
|||
// // 公用跳转方法 |
|||
// goToPage |
|||
// }); |
|||
// // 引入静态资源 |
|||
</script> |
|||
|
|||
<style> |
|||
uni-page-head { |
|||
display: none !important; |
|||
} |
|||
<style lang="scss"> |
|||
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */ |
|||
@import 'uview-plus/index.scss'; |
|||
</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