mirror of
https://gitee.com/niucloud-team/javashop.git
synced 2026-04-25 11:18:23 +00:00
0.0.2
This commit is contained in:
parent
7f0a8d746a
commit
490b56d4f1
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
/webroot/public/
|
||||||
|
/webroot/runtime/
|
||||||
364
pom.xml
Normal file
364
pom.xml
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<modules>
|
||||||
|
<!-- Maven将依次构建子模块 -->
|
||||||
|
<module>niucloud-core</module>
|
||||||
|
<module>niucloud-addon</module>
|
||||||
|
<module>niucloud-web-app</module>
|
||||||
|
<module>niucloud-boot</module>
|
||||||
|
</modules>
|
||||||
|
|
||||||
|
<groupId>com.niu</groupId>
|
||||||
|
<artifactId>niucloud-admin-java</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
<name>niucloud-admin-java</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<!-- 集成框架 -->
|
||||||
|
<spring-boot.version>2.7.18</spring-boot.version>
|
||||||
|
<spring-boot-satoken.version>1.38.0</spring-boot-satoken.version>
|
||||||
|
<swagger.version>3.0.0</swagger.version>
|
||||||
|
<quartz.version>2.7.2</quartz.version>
|
||||||
|
<log4j2.version>3.1.5</log4j2.version>
|
||||||
|
<!-- 持久框架 -->
|
||||||
|
<mysql-driver.version>8.0.21</mysql-driver.version>
|
||||||
|
<alibaba-druid.version>1.1.22</alibaba-druid.version>
|
||||||
|
<mybatis-plus.version>3.5.2</mybatis-plus.version>
|
||||||
|
<mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
|
||||||
|
<mybatis-plus-join.version>1.2.4</mybatis-plus-join.version>
|
||||||
|
<pagehelper.version>1.4.5</pagehelper.version>
|
||||||
|
<!-- 工具包类 -->
|
||||||
|
<commons-collections.version>3.2.2</commons-collections.version>
|
||||||
|
<commons-lang3.version>3.7</commons-lang3.version>
|
||||||
|
<hutool.version>5.8.27</hutool.version>
|
||||||
|
<guava.version>33.2.1-jre</guava.version>
|
||||||
|
<modelmapper.version>3.2.0</modelmapper.version>
|
||||||
|
<!-- 类库框架-->
|
||||||
|
<jackson.version>2.17.1</jackson.version>
|
||||||
|
<fastJson2.version>2.0.26</fastJson2.version>
|
||||||
|
<gson.version>2.11.0</gson.version>
|
||||||
|
<pinyin4j.version>2.5.1</pinyin4j.version>
|
||||||
|
<zxing.version>3.5.3</zxing.version>
|
||||||
|
<!-- 扩展框架 -->
|
||||||
|
<apache.httpcore5>5.2.4</apache.httpcore5>
|
||||||
|
<apache.httpclient5>5.3.1</apache.httpclient5>
|
||||||
|
<netty-all.version>4.1.110.Final</netty-all.version>
|
||||||
|
<easyexcel.version>3.3.3</easyexcel.version>
|
||||||
|
<weixin.version>4.6.0</weixin.version>
|
||||||
|
<!-- 辅助工具 -->
|
||||||
|
<lombok.version>1.18.24</lombok.version>
|
||||||
|
<alioss.version>3.17.4</alioss.version>
|
||||||
|
<qiniuoss.version>[7.13.0, 7.13.99]</qiniuoss.version>
|
||||||
|
<qcloud.version>5.6.219</qcloud.version>
|
||||||
|
<alisms.version>3.0.0</alisms.version>
|
||||||
|
<alipay.version>2.2.3</alipay.version>
|
||||||
|
<jtscore.version>1.18.1</jtscore.version>
|
||||||
|
<image-combiner.version>2.6.9</image-combiner.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<!--spring-boot-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-dependencies</artifactId>
|
||||||
|
<version>${spring-boot.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- ============================================================================= -->
|
||||||
|
<!--swagger3-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-boot-starter</artifactId>
|
||||||
|
<version>${swagger.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- spring-boot SA Token -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||||
|
<version>${spring-boot-satoken.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Sa-Token 整合 jwt -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-jwt</artifactId>
|
||||||
|
<version>${spring-boot-satoken.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Sa-Token整合Redis -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-redis-jackson</artifactId>
|
||||||
|
<version>${spring-boot-satoken.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Sa-Token插件:权限缓存与业务缓存分离 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-alone-redis</artifactId>
|
||||||
|
<version>${spring-boot-satoken.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Log4j2 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||||
|
<version>${log4j2.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- SLF4J API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>2.0.6</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ============================================================================= -->
|
||||||
|
<!-- Mysql-Connector -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>${mysql-driver.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!--alibaba-druid-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<version>${alibaba-druid.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- MyBatis-Plus -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- MyBatis-Plus添加代码生成器的依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-generator</artifactId>
|
||||||
|
<version>${mybatis-plus-generator.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- MyBatis-Plus-Join -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.yulichang</groupId>
|
||||||
|
<artifactId>mybatis-plus-join</artifactId>
|
||||||
|
<version>${mybatis-plus-join.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- PageHelper -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.pagehelper</groupId>
|
||||||
|
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||||
|
<version>${pagehelper.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ============================================================================= -->
|
||||||
|
<!-- Java集合工具包 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-collections</groupId>
|
||||||
|
<artifactId>commons-collections</artifactId>
|
||||||
|
<version>${commons-collections.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- commons.lang3-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- hutool-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-all</artifactId>
|
||||||
|
<version>${hutool.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- guava -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>${guava.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- modelmapper -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.modelmapper</groupId>
|
||||||
|
<artifactId>modelmapper</artifactId>
|
||||||
|
<version>${modelmapper.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ============================================================================= -->
|
||||||
|
<!-- Jackson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-annotations</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Fastjson2 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
<artifactId>fastjson2</artifactId>
|
||||||
|
<version>${fastJson2.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- gson -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- pinyin4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.belerweb</groupId>
|
||||||
|
<artifactId>pinyin4j</artifactId>
|
||||||
|
<version>${pinyin4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- zxing=>二维码 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.zxing</groupId>
|
||||||
|
<artifactId>core</artifactId>
|
||||||
|
<version>${zxing.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.zxing</groupId>
|
||||||
|
<artifactId>javase</artifactId>
|
||||||
|
<version>${zxing.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- EasyExcel -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>easyexcel</artifactId>
|
||||||
|
<version>${easyexcel.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 微信小程序 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-miniapp</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 微信公众号 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-mp</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!--微信开放平台-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-open</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 阿里云oss -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun.oss</groupId>
|
||||||
|
<artifactId>aliyun-sdk-oss</artifactId>
|
||||||
|
<version>${alioss.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 七牛云oss -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qiniu</groupId>
|
||||||
|
<artifactId>qiniu-java-sdk</artifactId>
|
||||||
|
<version>${qiniuoss.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 腾讯云oss -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.qcloud</groupId>
|
||||||
|
<artifactId>cos_api</artifactId>
|
||||||
|
<version>${qcloud.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 阿里云短信 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>dysmsapi20170525</artifactId>
|
||||||
|
<version>${alisms.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ============================================================================= -->
|
||||||
|
<!-- Apache httpcore5 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents.core5</groupId>
|
||||||
|
<artifactId>httpcore5</artifactId>
|
||||||
|
<version>${apache.httpcore5}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Apache httpclient5 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
|
<artifactId>httpclient5</artifactId>
|
||||||
|
<version>${apache.httpclient5}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- netty -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-all</artifactId>
|
||||||
|
<version>${netty-all.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- ============================================================================= -->
|
||||||
|
<!-- 公共类库 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-common</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 微信支付 SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-pay</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 微信小程序 SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-miniapp</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 公众号(订阅号、服务号)SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-mp</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 微信开放平台(第三方平台)SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.binarywang</groupId>
|
||||||
|
<artifactId>weixin-java-open</artifactId>
|
||||||
|
<version>${weixin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 支付宝支付-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alipay.sdk</groupId>
|
||||||
|
<artifactId>alipay-easysdk</artifactId>
|
||||||
|
<version>${alipay.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 空间分析 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.locationtech.jts</groupId>
|
||||||
|
<artifactId>jts-core</artifactId>
|
||||||
|
<version>${jtscore.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- 图片合成 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.freewayso</groupId>
|
||||||
|
<artifactId>image-combiner</artifactId>
|
||||||
|
<version>${image-combiner.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- 顶级父工程只声明 + 引入编译时工具依赖 -->
|
||||||
|
<!-- lombok插件-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
3
uni-app/.babelrc
Normal file
3
uni-app/.babelrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"presets": ["@babel/preset-env"]
|
||||||
|
}
|
||||||
25
uni-app/.env.development
Normal file
25
uni-app/.env.development
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
NODE_ENV = 'development'
|
||||||
|
|
||||||
|
# api请求地址
|
||||||
|
VITE_APP_BASE_URL = ''
|
||||||
|
|
||||||
|
# 图片服务器地址
|
||||||
|
VITE_IMG_DOMAIN = ''
|
||||||
|
|
||||||
|
# 站点id 仅在编译为小程序时生效
|
||||||
|
VITE_SITE_ID = ''
|
||||||
|
|
||||||
|
# 本地存储时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'
|
||||||
25
uni-app/.env.production
Normal file
25
uni-app/.env.production
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
NODE_ENV = 'production'
|
||||||
|
|
||||||
|
# api请求地址
|
||||||
|
VITE_APP_BASE_URL = ''
|
||||||
|
|
||||||
|
# 图片服务器地址
|
||||||
|
VITE_IMG_DOMAIN = ''
|
||||||
|
|
||||||
|
# 站点id 仅在编译为小程序时生效
|
||||||
|
VITE_SITE_ID = ''
|
||||||
|
|
||||||
|
# 本地存储时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'
|
||||||
21
uni-app/.gitignore
vendored
Normal file
21
uni-app/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
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
|
||||||
|
.idea
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
20
uni-app/index.html
Normal file
20
uni-app/index.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!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>
|
||||||
21866
uni-app/package-lock.json
generated
Normal file
21866
uni-app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
85
uni-app/package.json
Normal file
85
uni-app/package.json
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"name": "uni-preset-vue",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev:app": "uni -p app",
|
||||||
|
"dev:app-android": "uni -p app-android",
|
||||||
|
"dev:app-ios": "uni -p app-ios",
|
||||||
|
"dev:custom": "uni -p",
|
||||||
|
"dev:h5": "uni",
|
||||||
|
"dev:h5:ssr": "uni --ssr",
|
||||||
|
"dev:mp-alipay": "uni -p mp-alipay",
|
||||||
|
"dev:mp-baidu": "uni -p mp-baidu",
|
||||||
|
"dev:mp-jd": "uni -p mp-jd",
|
||||||
|
"dev:mp-kuaishou": "uni -p mp-kuaishou",
|
||||||
|
"dev:mp-lark": "uni -p mp-lark",
|
||||||
|
"dev:mp-qq": "uni -p mp-qq",
|
||||||
|
"dev:mp-toutiao": "uni -p mp-toutiao",
|
||||||
|
"dev:mp-weixin": "uni -p mp-weixin",
|
||||||
|
"dev:quickapp-webview": "uni -p quickapp-webview",
|
||||||
|
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
|
||||||
|
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
|
||||||
|
"build:app": "uni build -p app",
|
||||||
|
"build:app-android": "uni build -p app-android",
|
||||||
|
"build:app-ios": "uni build -p app-ios",
|
||||||
|
"build:custom": "uni build -p",
|
||||||
|
"build:h5": "uni build && node publish.cjs",
|
||||||
|
"build:h5:ssr": "uni build --ssr",
|
||||||
|
"build:mp-alipay": "uni build -p mp-alipay",
|
||||||
|
"build:mp-baidu": "uni build -p mp-baidu",
|
||||||
|
"build:mp-jd": "uni build -p mp-jd",
|
||||||
|
"build:mp-kuaishou": "uni build -p mp-kuaishou",
|
||||||
|
"build:mp-lark": "uni build -p mp-lark",
|
||||||
|
"build:mp-qq": "uni build -p mp-qq",
|
||||||
|
"build:mp-toutiao": "uni build -p mp-toutiao",
|
||||||
|
"build:mp-weixin": "uni build -p mp-weixin",
|
||||||
|
"build:quickapp-webview": "uni build -p quickapp-webview",
|
||||||
|
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
|
||||||
|
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||||
|
"type-check": "vue-tsc --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dcloudio/uni-app": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-app-plus": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-components": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-h5": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-alipay": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-baidu": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-jd": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-kuaishou": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-lark": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-qq": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-toutiao": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-mp-weixin": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-quickapp-webview": "3.0.0-3080720230703001",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"image-tools": "^1.4.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"pinia": "2.0.36",
|
||||||
|
"qrcode": "^1.5.1",
|
||||||
|
"qs": "6.7.0",
|
||||||
|
"sortablejs": "^1.15.0",
|
||||||
|
"uview-plus": "^3.1.29",
|
||||||
|
"vue": "^3.3.0",
|
||||||
|
"vue-i18n": "^9.2.2",
|
||||||
|
"weixin-js-sdk": "^1.6.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@dcasia/mini-program-tailwind-webpack-plugin": "^1.5.6",
|
||||||
|
"@dcloudio/types": "^3.3.2",
|
||||||
|
"@dcloudio/uni-automator": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-cli-shared": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/uni-stacktracey": "3.0.0-3080720230703001",
|
||||||
|
"@dcloudio/vite-plugin-uni": "3.0.0-3080720230703001",
|
||||||
|
"@rollup/plugin-commonjs": "^24.0.1",
|
||||||
|
"@types/qrcode": "^1.5.0",
|
||||||
|
"@types/sortablejs": "^1.15.0",
|
||||||
|
"@vue/tsconfig": "^0.1.3",
|
||||||
|
"sass": "^1.54.5",
|
||||||
|
"typescript": "^4.9.4",
|
||||||
|
"vite": "4.0.4",
|
||||||
|
"vite-plugin-windicss": "^1.8.10",
|
||||||
|
"vue-tsc": "^1.0.24",
|
||||||
|
"windicss": "^3.5.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
uni-app/public/niucloud.ico
Normal file
BIN
uni-app/public/niucloud.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
51
uni-app/publish.cjs
Normal file
51
uni-app/publish.cjs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
const publish = () => {
|
||||||
|
const src = './dist/build/h5'
|
||||||
|
const dest = '../webroot/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()
|
||||||
170
uni-app/src/App.vue
Normal file
170
uni-app/src/App.vue
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
|
||||||
|
import { launchInterceptor } from '@/utils/interceptor'
|
||||||
|
import { getToken, isWeixinBrowser, getSiteId, currRoute } 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
|
||||||
|
|
||||||
|
// #ifdef MP
|
||||||
|
const updateManager = uni.getUpdateManager();
|
||||||
|
updateManager.onCheckForUpdate(function(res) {
|
||||||
|
// 请求完新版本信息的回调
|
||||||
|
});
|
||||||
|
|
||||||
|
updateManager.onUpdateReady(function(res) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '更新提示',
|
||||||
|
content: '新版本已经准备好,是否重启应用?',
|
||||||
|
success(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||||
|
updateManager.applyUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
updateManager.onUpdateFailed(function(res) {
|
||||||
|
// 新的版本下载失败
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
await configStore.getTabbarConfig()
|
||||||
|
await configStore.getLoginConfig()
|
||||||
|
|
||||||
|
useSystemStore().getMapFn()
|
||||||
|
useSystemStore().getSiteInfoFn()
|
||||||
|
useMemberStore().getMemberLevel()
|
||||||
|
try {
|
||||||
|
// 隐藏tabbar
|
||||||
|
uni.hideTabBar()
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断在登录注册页面账号锁定后不进行请求三方登录注册
|
||||||
|
let url = currRoute()
|
||||||
|
if ((url == 'app/pages/auth/login' || url == 'app/pages/auth/register') && (configStore.login.is_username || configStore.login.is_mobile || configStore.login.is_bind_mobile)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否已登录
|
||||||
|
console.log(getToken())
|
||||||
|
if (getToken()) {
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
await memberStore.setToken(getToken())
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!uni.getStorageSync('openid')) {
|
||||||
|
const memberInfo = useMemberStore().info
|
||||||
|
const login = useLogin()
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
if (memberInfo && memberInfo.weapp_openid) {
|
||||||
|
uni.setStorageSync('openid', memberInfo.weapp_openid)
|
||||||
|
} else {
|
||||||
|
login.getAuthCode('', true)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
if (isWeixinBrowser()) {
|
||||||
|
if (memberInfo && memberInfo.wx_openid) {
|
||||||
|
uni.setStorageSync('openid', memberInfo.wx_openid)
|
||||||
|
} else {
|
||||||
|
data.query.code ? login.updateOpenid(data.query.code) : login.getAuthCode('snsapi_userinfo')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
// 开启强制绑定手机号
|
||||||
|
if (uni.getStorageSync('isbindmobile')) {
|
||||||
|
uni.removeStorageSync('isbindmobile');
|
||||||
|
}
|
||||||
|
if (configStore.login.is_bind_mobile && !memberStore.info.mobile) {
|
||||||
|
// 强制绑定手机号
|
||||||
|
uni.setStorageSync('isbindmobile', true)
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
if (!getToken()) {
|
||||||
|
// todo 退出后不进行自动登录
|
||||||
|
// #ifdef MP
|
||||||
|
if(uni.getStorageSync('autoLoginLock')){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// 判断是否开启第三方自动注册登录
|
||||||
|
if (configStore.login.is_auth_register) {
|
||||||
|
const login = useLogin()
|
||||||
|
// 第三方平台自动登录
|
||||||
|
// #ifdef MP
|
||||||
|
login.getAuthCode()
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
if (isWeixinBrowser()) {
|
||||||
|
console.log("authlogin", data)
|
||||||
|
data.query.code ? login.authLogin(data.query.code) : login.getAuthCode('snsapi_userinfo')
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
})
|
||||||
|
|
||||||
|
onHide(() => {
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
uni-page-head {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
29
uni-app/src/addon/components/diy/group/index.scss
Normal file
29
uni-app/src/addon/components/diy/group/index.scss
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.draggable-element,.ignore-draggable-element {
|
||||||
|
&.decorate {
|
||||||
|
&:hover:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 4rpx dotted $u-primary;
|
||||||
|
z-index: 10;
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 4rpx solid $u-primary;
|
||||||
|
z-index: 10;
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
92
uni-app/src/addon/components/diy/group/index.vue
Normal file
92
uni-app/src/addon/components/diy/group/index.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<view class="diy-group" id="componentList">
|
||||||
|
<top-tabbar :scrollBool="diyGroup.componentsScrollBool.TopTabbar" v-if="data.global && Object.keys(data.global).length && data.global.topStatusBar && data.global.topStatusBar.isShow" ref="topTabbarRef" :data="data.global" />
|
||||||
|
<view v-for="(component, index) in data.value" :key="component.id"
|
||||||
|
@click="diyStore.changeCurrentIndex(index, component)"
|
||||||
|
:class="diyGroup.getComponentClass(index,component)" :style="component.pageStyle">
|
||||||
|
<view class="relative" :style="{ marginTop : component.margin.top < 0 ? (component.margin.top * 2) + 'rpx' : '0' }">
|
||||||
|
<!-- 装修模式下,设置负上边距后超出的内容,禁止选中设置 -->
|
||||||
|
<view v-if="diyGroup.isShowPlaceHolder(index,component)" class="absolute w-full z-1" :style="{ height : (component.margin.top * 2 * -1) + 'rpx' }" @click.stop="diyGroup.placeholderEvent"></view>
|
||||||
|
<template v-if="component.componentName == 'ActiveCube'">
|
||||||
|
<diy-active-cube :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.ActiveCube" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'CarouselSearch'">
|
||||||
|
<diy-carousel-search :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.CarouselSearch" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'FloatBtn'">
|
||||||
|
<diy-float-btn :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.FloatBtn" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'GraphicNav'">
|
||||||
|
<diy-graphic-nav :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.GraphicNav" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'HorzBlank'">
|
||||||
|
<diy-horz-blank :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.HorzBlank" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'HorzLine'">
|
||||||
|
<diy-horz-line :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.HorzLine" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'HotArea'">
|
||||||
|
<diy-hot-area :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.HotArea" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'ImageAds'">
|
||||||
|
<diy-image-ads :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.ImageAds" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'MemberInfo'">
|
||||||
|
<diy-member-info :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.MemberInfo" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'MemberLevel'">
|
||||||
|
<diy-member-level :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.MemberLevel" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'Notice'">
|
||||||
|
<diy-notice :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.Notice" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'RichText'">
|
||||||
|
<diy-rich-text :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.RichText" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'RubikCube'">
|
||||||
|
<diy-rubik-cube :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.RubikCube" />
|
||||||
|
</template>
|
||||||
|
<template v-if="component.componentName == 'Text'">
|
||||||
|
<diy-text :component="component" :global="data.global" :index="index" :pullDownRefreshCount="props.pullDownRefreshCount" :scrollBool="diyGroup.componentsScrollBool.Text" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<template v-if="diyStore.mode == '' && data.global.bottomTabBarSwitch">
|
||||||
|
<view class="pt-[20rpx]"></view>
|
||||||
|
<tabbar />
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
import topTabbar from '@/components/top-tabbar/top-tabbar.vue'
|
||||||
|
import useDiyStore from '@/app/stores/diy';
|
||||||
|
import { useDiyGroup } from './useDiyGroup';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps(['data','pullDownRefreshCount']);
|
||||||
|
const topTabbarRef = ref(null);
|
||||||
|
const diyStore = useDiyStore();
|
||||||
|
const diyGroup = useDiyGroup({
|
||||||
|
...props,
|
||||||
|
getFormRef() {
|
||||||
|
return {
|
||||||
|
topTabbarRef: topTabbarRef.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = ref(diyGroup.data);
|
||||||
|
|
||||||
|
// 监听页面加载完成
|
||||||
|
diyGroup.onMounted();
|
||||||
|
|
||||||
|
// 监听滚动事件
|
||||||
|
diyGroup.onPageScroll();
|
||||||
|
defineExpose({
|
||||||
|
refresh: diyGroup.refresh
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
162
uni-app/src/addon/components/diy/group/useDiyGroup.ts
Normal file
162
uni-app/src/addon/components/diy/group/useDiyGroup.ts
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
import { ref, reactive, onMounted, nextTick, computed } from 'vue';
|
||||||
|
import Sortable from 'sortablejs';
|
||||||
|
import { range } from 'lodash-es';
|
||||||
|
import { onPageScroll, onHide, onShow } from '@dcloudio/uni-app';
|
||||||
|
import useDiyStore from '@/app/stores/diy';
|
||||||
|
import { getLocation } from '@/utils/common';
|
||||||
|
|
||||||
|
export function useDiyGroup(params: any = {}) {
|
||||||
|
|
||||||
|
let scrollVal: any = ""; //组件滚动值集合
|
||||||
|
const componentsScrollBool: any = ref({}); //组件是否根据滚动进行相应改变
|
||||||
|
const diyStore = useDiyStore();
|
||||||
|
|
||||||
|
const positionFixed = ref(['fixed', 'top_fixed', 'right_fixed', 'bottom_fixed', 'left_fixed']);
|
||||||
|
|
||||||
|
const data = computed(() => {
|
||||||
|
if (diyStore.mode == 'decorate') {
|
||||||
|
return diyStore;
|
||||||
|
} else {
|
||||||
|
return params.data;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getComponentClass = (index: any, component: any) => {
|
||||||
|
let obj: any = {
|
||||||
|
relative: true,
|
||||||
|
selected: diyStore.currentIndex == index,
|
||||||
|
decorate: diyStore.mode == 'decorate'
|
||||||
|
}
|
||||||
|
obj['top-fixed-' + diyStore.topFixedStatus] = true;
|
||||||
|
|
||||||
|
if (component.position && positionFixed.value.indexOf(component.position) != -1) {
|
||||||
|
// 找出置顶组件,设置禁止拖动
|
||||||
|
obj['ignore-draggable-element'] = true;
|
||||||
|
} else {
|
||||||
|
obj['draggable-element'] = true;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否显示占位区域,用于禁止选中负上边距的内容
|
||||||
|
const isShowPlaceHolder = (index: any, component: any) => {
|
||||||
|
// #ifdef H5
|
||||||
|
if (diyStore.mode == 'decorate') {
|
||||||
|
let el: any = document.getElementById('componentList');
|
||||||
|
if (el && el.children.length && el.children[index]) {
|
||||||
|
let height = el.children[index].offsetHeight;
|
||||||
|
let top = 0;
|
||||||
|
if (component.margin.top < 0) {
|
||||||
|
top = component.margin.top * 2 * -1;
|
||||||
|
// 若负上边距大于组件的高度,则允许选中进行装修
|
||||||
|
if (top > height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 监听页面加载完成
|
||||||
|
const onMountedLifeCycle = () => {
|
||||||
|
onMounted(() => {
|
||||||
|
// #ifdef H5
|
||||||
|
if (diyStore.mode == 'decorate') {
|
||||||
|
var el = document.getElementById('componentList');
|
||||||
|
const sortable = Sortable.create(el, {
|
||||||
|
draggable: '.draggable-element',
|
||||||
|
animation: 200,
|
||||||
|
// 结束拖拽
|
||||||
|
onEnd: event => {
|
||||||
|
let temp = diyStore.value[event.oldIndex!];
|
||||||
|
diyStore.value.splice(event.oldIndex!, 1);
|
||||||
|
diyStore.value.splice(event.newIndex!, 0, temp);
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
sortable.sort(range(diyStore.value.length).map((value: any) => {
|
||||||
|
return value.toString();
|
||||||
|
}));
|
||||||
|
|
||||||
|
diyStore.postMessage(event.newIndex, diyStore.value[event.newIndex]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (data.value.global && data.value.global.topStatusBar && data.value.global.topStatusBar.style == 'style-4') {
|
||||||
|
// 第一次获取经纬度
|
||||||
|
getLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化组件滚动值
|
||||||
|
scrollVal = uni.getStorageSync('componentsScrollValGroup');
|
||||||
|
if (scrollVal) {
|
||||||
|
for (let key in scrollVal) {
|
||||||
|
componentsScrollBool.value[key] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面onShow调用时,也会触发改方法
|
||||||
|
const refresh = () => {
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
params.getFormRef().topTabbarRef?.refresh();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 空函数,禁止选中
|
||||||
|
const placeholderEvent = () => {
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPagesHide = ref(false)
|
||||||
|
onShow(() => {
|
||||||
|
isPagesHide.value = false;
|
||||||
|
})
|
||||||
|
onHide(() => {
|
||||||
|
isPagesHide.value = true;
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听滚动事件
|
||||||
|
const scrollValStr = ref()
|
||||||
|
const onPageScrollLifeCycle = () => {
|
||||||
|
onPageScroll((e) => {
|
||||||
|
if (scrollVal && !isPagesHide.value) {
|
||||||
|
for (let key in scrollVal) {
|
||||||
|
if (e.scrollTop <= 0) {
|
||||||
|
// -1 表示页面滚动值小于零,组件随页面下拉而下来
|
||||||
|
componentsScrollBool.value[key] = -1;
|
||||||
|
} else if (e.scrollTop > scrollVal[key]) {
|
||||||
|
// 1 表示页面滚动值大于传入滚动值,组件随页面上拉背景、文字颜色等采用滚动后的变量
|
||||||
|
componentsScrollBool.value[key] = 1;
|
||||||
|
} else {
|
||||||
|
// 2 表示页面滚动值小于传入滚动值,组件随页面下拉背景、文字颜色等采用滚动前的变量
|
||||||
|
componentsScrollBool.value[key] = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
scrollV: scrollValStr.value,
|
||||||
|
data: data.value,
|
||||||
|
componentsScrollBool: componentsScrollBool.value,
|
||||||
|
placeholderEvent,
|
||||||
|
refresh,
|
||||||
|
isShowPlaceHolder,
|
||||||
|
getComponentClass,
|
||||||
|
onPageScroll: onPageScrollLifeCycle,
|
||||||
|
onMounted: onMountedLifeCycle
|
||||||
|
}
|
||||||
|
}
|
||||||
0
uni-app/src/addon/components/fixed/group/index.scss
Normal file
0
uni-app/src/addon/components/fixed/group/index.scss
Normal file
15
uni-app/src/addon/components/fixed/group/index.vue
Normal file
15
uni-app/src/addon/components/fixed/group/index.vue
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<template>
|
||||||
|
<view class="fixed-group">
|
||||||
|
<template v-if="props.data.global.component == 'demo-index'">
|
||||||
|
<fixed-demo-index :data="props.data" :pullDownRefreshCount="props.pullDownRefreshCount"></fixed-demo-index>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
|
||||||
|
const props = defineProps(['data','pullDownRefreshCount']);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
8
uni-app/src/addon/end.vue
Normal file
8
uni-app/src/addon/end.vue
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
</style>
|
||||||
118
uni-app/src/app/api/auth.ts
Normal file
118
uni-app/src/app/api/auth.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
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) {
|
||||||
|
if(uni.getStorageSync('pid')){
|
||||||
|
data.pid = uni.getStorageSync('pid');
|
||||||
|
}
|
||||||
|
return request.post('wechat/userlogin', data, { showErrorMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信公众号授权登录
|
||||||
|
*/
|
||||||
|
export function wechatLogin(data : AnyObject) {
|
||||||
|
if(uni.getStorageSync('pid')){
|
||||||
|
data.pid = uni.getStorageSync('pid');
|
||||||
|
}
|
||||||
|
return request.post('wechat/login', data, { showErrorMessage: false })
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 微信公众号号修改openid
|
||||||
|
*/
|
||||||
|
export function updateWechatOpenid(data : AnyObject) {
|
||||||
|
return request.put('wechat/update_openid', data, { showErrorMessage: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信小程序授权登录
|
||||||
|
*/
|
||||||
|
export function weappLogin(data : AnyObject) {
|
||||||
|
if(uni.getStorageSync('pid')){
|
||||||
|
data.pid = uni.getStorageSync('pid');
|
||||||
|
}
|
||||||
|
return request.post('weapp/login', data, { showErrorMessage: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信小程序修改openid
|
||||||
|
*/
|
||||||
|
export function updateWeappOpenid(data : AnyObject) {
|
||||||
|
return request.put('weapp/update_openid', 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 })
|
||||||
|
}
|
||||||
29
uni-app/src/app/api/diy.ts
Normal file
29
uni-app/src/app/api/diy.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
249
uni-app/src/app/api/member.ts
Normal file
249
uni-app/src/app/api/member.ts
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
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 getPointType(account_type : string) {
|
||||||
|
return request.get(`member/account/fromtype/${account_type}`)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取不可提现余额流水
|
||||||
|
*/
|
||||||
|
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`)
|
||||||
|
}
|
||||||
15
uni-app/src/app/api/pay.ts
Normal file
15
uni-app/src/app/api/pay.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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 })
|
||||||
|
}
|
||||||
147
uni-app/src/app/api/system.ts
Normal file
147
uni-app/src/app/api/system.ts
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
43
uni-app/src/app/api/verify.ts
Normal file
43
uni-app/src/app/api/verify.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
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 }`, {}, { showErrorMessage: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取核销详情
|
||||||
|
*/
|
||||||
|
export function getVerifyDetail(code: string) {
|
||||||
|
return request.get(`verify_detail/${ code }`, {}, { showErrorMessage: true })
|
||||||
|
}
|
||||||
249
uni-app/src/app/components/diy/active-cube/index.vue
Normal file
249
uni-app/src/app/components/diy/active-cube/index.vue
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
<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" :id="'warpStyle3-'+diyComponent.id" v-if="diyComponent.blockStyle.value == 'style-3'">
|
||||||
|
<view v-for="(item,index) in diyComponent.list" :key="item.id" class="inline-flex">
|
||||||
|
<view :id="'item'+index+diyComponent.id" @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" :style="itemStyle3" :class="{'!mr-[0rpx]': 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" :id="'warpStyle4-'+diyComponent.id" v-if="diyComponent.blockStyle.value == 'style-4'">
|
||||||
|
<view v-for="(item,index) in diyComponent.list" :key="item.id" class="inline-flex">
|
||||||
|
<view :id="'item'+index+diyComponent.id" @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-[0rpx]': index+1 === diyComponent.list.length}" :style="'background :linear-gradient('+ item.listFrame.startColor +','+ item.listFrame.endColor + ');'+itemStyle4">
|
||||||
|
<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 itemStyle3 = ref('');
|
||||||
|
const setItemStyle3 = ()=>{
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.createSelectorQuery().in(instance).select('#warpStyle3-'+diyComponent.value.id).boundingClientRect((res:any) => {
|
||||||
|
uni.createSelectorQuery().in(instance).select('#item0'+diyComponent.value.id).boundingClientRect((data:any) => {
|
||||||
|
itemStyle3.value = `margin-right:${(res.width - data.width*4)/3}px;`
|
||||||
|
}).exec()
|
||||||
|
}).exec()
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
itemStyle3.value= 'margin-right:14rpx;'
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
//商品样式四
|
||||||
|
const itemStyle4 = ref('');
|
||||||
|
const setItemStyle4 = ()=>{
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.createSelectorQuery().in(instance).select('#warpStyle4-'+diyComponent.value.id).boundingClientRect((res:any) => {
|
||||||
|
uni.createSelectorQuery().in(instance).select('#item0'+diyComponent.value.id).boundingClientRect((data:any) => {
|
||||||
|
itemStyle4.value = `margin-right:${(res.width - data.width*4)/3}px;`
|
||||||
|
|
||||||
|
}).exec()
|
||||||
|
}).exec()
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
itemStyle4.value= 'margin-right:14rpx;'
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
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();
|
||||||
|
|
||||||
|
if(diyComponent.value.blockStyle.value == 'style-3') setItemStyle3()
|
||||||
|
if(diyComponent.value.blockStyle.value == 'style-4') setItemStyle4()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.active-cube-wrap {
|
||||||
|
.bd {
|
||||||
|
.item {
|
||||||
|
width: calc(46% - 20rpx);
|
||||||
|
|
||||||
|
image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
656
uni-app/src/app/components/diy/carousel-search/index.vue
Normal file
656
uni-app/src/app/components/diy/carousel-search/index.vue
Normal file
@ -0,0 +1,656 @@
|
|||||||
|
<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" :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" @click="diyStore.toRedirect(diyComponent.search.link)">
|
||||||
|
<text class="input-content text-[#fff] text-[24rpx] leading-[68rpx]">{{isShowSearchPlaceholder ? diyComponent.search.text : ''}}</text>
|
||||||
|
<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' && props.scrollBool != -1" 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', 'scrollBool']);
|
||||||
|
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') {
|
||||||
|
if (props.scrollBool != -1) {
|
||||||
|
style += 'position: fixed;z-index: 10;left: 0;right: 0;';
|
||||||
|
}
|
||||||
|
|
||||||
|
// #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 (props.scrollBool == 1) {
|
||||||
|
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' && props.scrollBool == 1) {
|
||||||
|
color = diyComponent.value.tab.fixedSelectColor;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
color = diyComponent.value.tab.noColor;
|
||||||
|
if(diyComponent.value.positionWay == 'fixed' && props.scrollBool == 1) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabAllPopup = ref(false);
|
||||||
|
let menuButtonInfo:any = {};
|
||||||
|
const 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
|
||||||
|
|
||||||
|
/******************************* 存储滚动值-start ***********************/
|
||||||
|
// 键名和组件名一致即可
|
||||||
|
let componentsScrollVal = uni.getStorageSync('componentsScrollValGroup')
|
||||||
|
if(componentsScrollVal && (typeof componentsScrollVal == "object")){
|
||||||
|
componentsScrollVal.CarouselSearch = 20
|
||||||
|
uni.setStorageSync('componentsScrollValGroup', componentsScrollVal);
|
||||||
|
}else{
|
||||||
|
let obj = {
|
||||||
|
CarouselSearch: 20
|
||||||
|
}
|
||||||
|
uni.setStorageSync('componentsScrollValGroup', obj);
|
||||||
|
}
|
||||||
|
/******************************* 存储滚动值-end ***********************/
|
||||||
|
|
||||||
|
</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 32rpx;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
background-color: rgba(255,255,255,.2);
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
.input-content, .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 :deep(.uni-swiper-dot) {
|
||||||
|
width: 12rpx;
|
||||||
|
height: 12rpx;
|
||||||
|
}
|
||||||
|
.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: 12rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 12rpx;
|
||||||
|
margin: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.straightLine {
|
||||||
|
.swiper-dot {
|
||||||
|
width: 18rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
width: 36rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
173
uni-app/src/app/components/diy/float-btn/index.vue
Normal file
173
uni-app/src/app/components/diy/float-btn/index.vue
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<view class="float-btn fixed z-1000" :class="[diyComponent.style,diyComponent.bottomPosition, diyStore.mode == 'decorate' ? 'float-btn-border' : '']" :style="floatBtnWrapCss">
|
||||||
|
<view v-if="diyComponent.style==='style-1'" class="flex flex-col items-center p-[24rpx]" :style="warpCss">
|
||||||
|
<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 v-if="diyComponent.style==='style-2'" class="relative w-[3rpx] h-[3rpx]">
|
||||||
|
<view class="py-[14rpx] overflow-hidden absolute right-[25rpx] top-[1rpx] transform -translate-y-1/2" :style="styleTwoWarpCss">
|
||||||
|
<swiper :style="{'width':diyComponent.imageSize * 2+24+'rpx','height':diyComponent.imageSize * 2+44+'rpx !important',}" circular>
|
||||||
|
<swiper-item v-for="(item,index) in diyComponent.list" :key="index">
|
||||||
|
<view @click="diyStore.toRedirect(item.link)" class="px-[12rpx] flex flex-col items-center justify-center">
|
||||||
|
<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 class="text-[24rpx] text-[303133] text-center mt-[20rpx]">{{ item.link.title }}</view>
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
<view class="w-[60rpx] h-[60rpx] absolute right-[-64rpx] top-[1rpx] transform -translate-y-1/2 rounded-[30rpx] flex items-center" :style="styleTwoSphere">
|
||||||
|
<text class="!text-[60rpx] iconfont iconxiaolian-1 text-[var(--primary-color)] font-400 transform rotate-90 translate-x-[-13rpx]"></text>
|
||||||
|
</view>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
// 浮动按钮组件
|
||||||
|
import { computed, watch,ref } from 'vue';
|
||||||
|
import { onPageScroll } from '@dcloudio/uni-app';
|
||||||
|
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 += 'transform: translateY('+ ((-diyComponent.value.offset) * 2) + 'rpx)';
|
||||||
|
}else if(diyComponent.value.bottomPosition == 'upperRight' || diyComponent.value.bottomPosition == 'upperLeft'){
|
||||||
|
style += 'transform: translateX('+ diyComponent.value.offset * 2 + 'rpx);';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
})
|
||||||
|
|
||||||
|
//样式二
|
||||||
|
const styleTwoRepeat = ref(true)
|
||||||
|
const styleTwoRepeatTime = ref(null)
|
||||||
|
const styleTwoWarpCss = 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;';
|
||||||
|
style += 'transition: right .25s;box-shadow:0px 32rpx 96rpx 32rpx rgba(0, 0, 0, .08), 0px 24rpx 64px rgba(0, 0, 0, .12), 0px 16rpx 32rpx -16rpx rgba(0, 0, 0, .16);'
|
||||||
|
style +=styleTwoRepeat.value?'transition-delay: 0.25s;':('right:-'+(diyComponent.value.imageSize * 2+24)+'rpx !important;');
|
||||||
|
return style;
|
||||||
|
})
|
||||||
|
|
||||||
|
const styleTwoSphere = computed(()=>{
|
||||||
|
var style = 'transition: right .25s;background: rgba(0, 0, 0, 0.5);';
|
||||||
|
style +=styleTwoRepeat.value?'':'right:-32rpx !important;transition-delay: 0.25s;';
|
||||||
|
return style
|
||||||
|
})
|
||||||
|
|
||||||
|
onPageScroll(() => {
|
||||||
|
if(diyComponent.value.style==='style-2'){
|
||||||
|
if(styleTwoRepeatTime) clearTimeout(styleTwoRepeatTime.value)
|
||||||
|
styleTwoRepeat.value = false
|
||||||
|
styleTwoRepeatTime.value = setTimeout(()=>{
|
||||||
|
styleTwoRepeat.value = true
|
||||||
|
clearTimeout(styleTwoRepeatTime.value)
|
||||||
|
},200)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.pullDownRefreshCount,
|
||||||
|
(newValue, oldValue) => {
|
||||||
|
// 处理下拉刷新业务
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.float-btn{
|
||||||
|
&.upperLeft {
|
||||||
|
top: 100rpx;
|
||||||
|
left: 30rpx;
|
||||||
|
&.style-2{
|
||||||
|
left:0 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.upperRight {
|
||||||
|
top: 100rpx;
|
||||||
|
right: 30rpx;
|
||||||
|
&.style-2{
|
||||||
|
right:0 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.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*/
|
||||||
|
&.style-2{
|
||||||
|
left:0 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&.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*/
|
||||||
|
&.style-2{
|
||||||
|
right:0 ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.z-1000{
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.float-btn-border{
|
||||||
|
border: 4rpx dashed var(--primary-color);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
336
uni-app/src/app/components/diy/graphic-nav/index.vue
Normal file
336
uni-app/src/app/components/diy/graphic-nav/index.vue
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
<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="[diyComponent.mode]" :key="item.id" v-if="swiperCondition(index,numItem)" :style="{ width: 100 / diyComponent.rowCount + '%' }">
|
||||||
|
|
||||||
|
<view @click="diyStore.toRedirect(item.link)" class="graphic-nav-item 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-if="diyComponent.layout == 'horizontal' && diyComponent.pageCount == 2 && diyComponent.showStyle == 'singleSlide'" :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 :style="horizontalSingleSlideStyle" class="flex">
|
||||||
|
<view class="graphic-nav-wrap flex flex-wrap" :style="horizontalSingleSlideBoxStyle(numIndex)" v-for="(numItem, numIndex) in Math.ceil(diyComponent.list.length / (diyComponent.pageCount * diyComponent.rowCount))">
|
||||||
|
<template v-for="(item, index) in diyComponent.list">
|
||||||
|
|
||||||
|
<view v-if="swiperCondition(index,numItem)" @click="diyStore.toRedirect(item.link)" :style="horizontalSingleSlideItemStyle(numIndex)" class="graphic-nav-item 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>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- #ifdef MP -->
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<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;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 多行,单行滑动样式
|
||||||
|
const horizontalSingleSlideStyle = computed(()=>{
|
||||||
|
let style = {width: ""};
|
||||||
|
let widthStr = 100 / diyComponent.value.rowCount; // 表示每项宽度
|
||||||
|
let itemLen = (parseInt(diyComponent.value.list.length / (diyComponent.value.rowCount*2))*diyComponent.value.rowCount) + (diyComponent.value.list.length%(diyComponent.value.rowCount*2)); // 表示展示几列
|
||||||
|
let marginLen = diyComponent.value.margin.both*4
|
||||||
|
style.width = `calc(${widthStr * itemLen}vw - ${marginLen}rpx)`;
|
||||||
|
return style;
|
||||||
|
})
|
||||||
|
|
||||||
|
const horizontalSingleSlideBoxStyle = (index: any)=>{
|
||||||
|
let style = {width: ""};
|
||||||
|
let widthStr = 100 / diyComponent.value.rowCount; // 表示每项宽度
|
||||||
|
let marginLen = diyComponent.value.margin.both * 4 / diyComponent.value.rowCount;
|
||||||
|
if(parseInt(diyComponent.value.list.length / (diyComponent.value.rowCount*2)) >= (index+1)){
|
||||||
|
style.width = `calc(${widthStr * diyComponent.value.rowCount}vw - ${marginLen*diyComponent.value.rowCount}rpx)`;
|
||||||
|
}else{
|
||||||
|
let len = diyComponent.value.list.length%(diyComponent.value.rowCount*2);
|
||||||
|
if(len > diyComponent.value.rowCount){ // 满足了一行,但没有满足于一页
|
||||||
|
style.width = `calc(${widthStr * diyComponent.value.rowCount}vw - ${marginLen*diyComponent.value.rowCount}rpx)`;
|
||||||
|
}else{
|
||||||
|
style.width = `calc(${widthStr * len}vw - ${marginLen * len}rpx)`; // 未满足了一行
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
const horizontalSingleSlideItemStyle = (index: any)=>{
|
||||||
|
let style = {width: ""};
|
||||||
|
if(parseInt(diyComponent.value.list.length / (diyComponent.value.rowCount*2)) >= (index+1)){
|
||||||
|
style.width = `${100 / diyComponent.value.rowCount}%`;
|
||||||
|
}else{
|
||||||
|
let len = diyComponent.value.list.length%(diyComponent.value.rowCount*2);
|
||||||
|
if(len > diyComponent.value.rowCount){ // 满足了一行,但没有满足于一页
|
||||||
|
style.width = `${100 / diyComponent.value.rowCount}%`;
|
||||||
|
}else{
|
||||||
|
style.width = `${100 / len}%`; // 未满足了一行
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
result = index >= [(numItem - 1) * (count)] && index < [numItem * (count)];
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
let len = 1;
|
||||||
|
if(diyComponent.value.pageCount == 2){
|
||||||
|
len = (diyComponent.value.list.length / diyComponent.value.rowCount) > 1 ? 2 : 1 ;
|
||||||
|
}
|
||||||
|
height = data.height * len;
|
||||||
|
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>
|
||||||
44
uni-app/src/app/components/diy/horz-blank/index.vue
Normal file
44
uni-app/src/app/components/diy/horz-blank/index.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<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>
|
||||||
40
uni-app/src/app/components/diy/horz-line/index.vue
Normal file
40
uni-app/src/app/components/diy/horz-line/index.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<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>
|
||||||
91
uni-app/src/app/components/diy/hot-area/index.vue
Normal file
91
uni-app/src/app/components/diy/hot-area/index.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<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>
|
||||||
140
uni-app/src/app/components/diy/image-ads/index.vue
Normal file
140
uni-app/src/app/components/diy/image-ads/index.vue
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<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>
|
||||||
206
uni-app/src/app/components/diy/member-info/index.vue
Normal file
206
uni-app/src/app/components/diy/member-info/index.vue
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<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" :default-url="img('static/resource/images/default_headimg.png')" @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" :default-url="img('static/resource/images/default_headimg.png')" />
|
||||||
|
<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 -->
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #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'
|
||||||
|
import useConfigStore from '@/stores/config'
|
||||||
|
|
||||||
|
const props = defineProps(['component', 'index', 'pullDownRefreshCount','global']);
|
||||||
|
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
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 = () => {
|
||||||
|
if(configStore.login.is_username || configStore.login.is_mobile || configStore.login.is_bind_mobile){
|
||||||
|
useLogin().setLoginBack({ url: '/app/pages/member/index' })
|
||||||
|
}else if(configStore.login.is_auth_register){ // 判断是否开启第三方自动注册登录
|
||||||
|
// 第三方平台自动登录
|
||||||
|
// #ifdef MP
|
||||||
|
useLogin().getAuthCode()
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
if (isWeixinBrowser()) {
|
||||||
|
useLogin().getAuthCode('snsapi_userinfo')
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}else{
|
||||||
|
uni.showToast({ title: '商家未开启注册方式', icon: 'none' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
220
uni-app/src/app/components/diy/member-level/index.vue
Normal file
220
uni-app/src/app/components/diy/member-level/index.vue
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
<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 flex-1">
|
||||||
|
<view class="flex items-center justify-between">
|
||||||
|
<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>
|
||||||
|
<view class="flex items-center" @click="toLink('/app/pages/member/level')">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<image :src="img('static/resource/images/diy/member/rule.png')" mode="aspectFit" class="w-[20rpx] h-[20rpx]" />
|
||||||
|
<text class="text-[18rpx] text-[#733F02] ml-[6rpx] leading-[24rpx]">规则</text>
|
||||||
|
</view>
|
||||||
|
<view class="ml-[6rpx] text-[#733F02] !text-[26rpx] nc-iconfont nc-icon-youV6xx"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<text class="text-[28rpx] text-[#794200] mt-[16rpx]">购物或邀请好友可以提升等级</text>
|
||||||
|
</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] leading-[1.4] 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) => {
|
||||||
|
// 处理下拉刷新业务
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 获取会员等级列表
|
||||||
|
const upgradeGrowth = ref(0) // 升级下级会员所需的成长值
|
||||||
|
const currIndex = ref(0) //当前会员索引
|
||||||
|
const afterCurrIndex = ref(-1) // 下一个会员等级索引
|
||||||
|
const benefits_arr:any = ref([]) //当前会员权益
|
||||||
|
const wap_member_info = ref(uni.getStorageSync('wap_member_info'));
|
||||||
|
const info:any = computed(() => {
|
||||||
|
// 装修模式
|
||||||
|
if (diyStore.mode == 'decorate') {
|
||||||
|
upgradeGrowth.value = 0;
|
||||||
|
benefits_arr.value = [{'title': '商品包邮'}];
|
||||||
|
currIndex.value = 1;
|
||||||
|
return {
|
||||||
|
member_level_name: '会员等级',
|
||||||
|
growth: 5
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return wap_member_info.value||{};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const list:any = computed(() => {
|
||||||
|
// 装修模式
|
||||||
|
if (diyStore.mode == 'decorate') {
|
||||||
|
return [{}];
|
||||||
|
}else{
|
||||||
|
getMemberLevelFn(memberStore.levelList)
|
||||||
|
return memberStore.levelList
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
const getMemberLevelFn = (list:any)=> {
|
||||||
|
if(!list||!list.length) return false;
|
||||||
|
let isSet = false;
|
||||||
|
// 刚进来处理会员等级数据
|
||||||
|
if (info.value && list && list.length) {
|
||||||
|
list.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.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list[afterCurrIndex.value] && list[afterCurrIndex.value].growth) {
|
||||||
|
upgradeGrowth.value = list[afterCurrIndex.value].growth - info.value.growth;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// 当前会员没有会员等级,则展示会员等级中的最后一个等级
|
||||||
|
info.value.member_level_name = list[0].level_name;
|
||||||
|
upgradeGrowth.value = list[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>
|
||||||
303
uni-app/src/app/components/diy/notice/index.vue
Normal file
303
uni-app/src/app/components/diy/notice/index.vue
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
<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-[30rpx] flex-shrink-0" mode="heightFix" />
|
||||||
|
</template>
|
||||||
|
<image v-else-if="diyComponent.imgType == 'diy'" :src="img(diyComponent.imageUrl || '')" class="w-[200rpx] h-[30rpx] 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-'+diyComponent.id" :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" v-if="marqueeBodyWidth < (marqueeOneWidth-30)">
|
||||||
|
<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 marqueeOneWidth = ref(0); // 内容宽度
|
||||||
|
const marqueeStyle = ref(''); // 横向滚动样式
|
||||||
|
const time = ref(0); // 滚动完成时间
|
||||||
|
const delayTime = ref(800); // 动画延迟时间
|
||||||
|
|
||||||
|
// 绑定横向滚动事件
|
||||||
|
const bindCrossSlipEvent = ()=> {
|
||||||
|
if (diyComponent.value.scrollWay == 'horizontal') {
|
||||||
|
setTimeout(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.createSelectorQuery().in(instance).select('#horizontal-body-' + diyComponent.value.id).boundingClientRect(res => {
|
||||||
|
marqueeBodyWidth.value = res.width;
|
||||||
|
const query = uni.createSelectorQuery().in(instance);
|
||||||
|
query.select('#horizontal-body-' + diyComponent.value.id + ' .marquee-one').boundingClientRect((data: any) => {
|
||||||
|
marqueeOneWidth.value = data.width
|
||||||
|
time.value = Math.ceil(marqueeOneWidth.value * 14);
|
||||||
|
if (marqueeBodyWidth.value > (marqueeOneWidth.value-30)) {
|
||||||
|
marqueeStyle.value = `animation: none;`;
|
||||||
|
} else {
|
||||||
|
marqueeStyle.value = `
|
||||||
|
animation-duration: ${ time.value }ms;
|
||||||
|
animation-delay: ${ delayTime.value }ms;`;
|
||||||
|
}
|
||||||
|
}).exec();
|
||||||
|
}).exec();
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
let documentObj = window.document.getElementById('horizontal-body-' + diyComponent.value.id);
|
||||||
|
let marqueeOne = window.document.getElementById('marquee-one');
|
||||||
|
if(documentObj && marqueeOne) {
|
||||||
|
marqueeBodyWidth.value = documentObj.offsetWidth;
|
||||||
|
marqueeOneWidth.value = marqueeOne.offsetWidth;
|
||||||
|
time.value = Math.ceil(marqueeOneWidth.value * 14);
|
||||||
|
if (marqueeBodyWidth.value > (marqueeOneWidth.value-30)) {
|
||||||
|
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.link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.marquee {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding-right: 30px;
|
||||||
|
|
||||||
|
// -webkit-perspective: 1000;
|
||||||
|
// -moz-perspective: 1000;
|
||||||
|
// -ms-perspective: 1000;
|
||||||
|
// perspective: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes marquee {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
20%{
|
||||||
|
transform: translateX(-10%);
|
||||||
|
}
|
||||||
|
40%{
|
||||||
|
transform: translateX(-20%);
|
||||||
|
}
|
||||||
|
60%{
|
||||||
|
transform: translateX(-30%);
|
||||||
|
}
|
||||||
|
80%{
|
||||||
|
transform: translateX(-40%);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
125
uni-app/src/app/components/diy/rich-text/index.vue
Normal file
125
uni-app/src/app/components/diy/rich-text/index.vue
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<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>
|
||||||
590
uni-app/src/app/components/diy/rubik-cube/index.vue
Normal file
590
uni-app/src/app/components/diy/rubik-cube/index.vue
Normal file
@ -0,0 +1,590 @@
|
|||||||
|
<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>
|
||||||
129
uni-app/src/app/components/diy/text/index.vue
Normal file
129
uni-app/src/app/components/diy/text/index.vue
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<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>
|
||||||
15
uni-app/src/app/components/fixed/demo-index/index.vue
Normal file
15
uni-app/src/app/components/fixed/demo-index/index.vue
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<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>
|
||||||
6
uni-app/src/app/locale/en/pages.setting.index.json
Normal file
6
uni-app/src/app/locale/en/pages.setting.index.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"personalSettings": "Personal settings",
|
||||||
|
"switchLang": "Switch language",
|
||||||
|
"version": "Version",
|
||||||
|
"logout": "Log out"
|
||||||
|
}
|
||||||
5
uni-app/src/app/locale/zh-Hans/pages.article.detail.json
Normal file
5
uni-app/src/app/locale/zh-Hans/pages.article.detail.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"detail": "文章详情",
|
||||||
|
"abstract": "摘要",
|
||||||
|
"loadingText": "正在加载"
|
||||||
|
}
|
||||||
7
uni-app/src/app/locale/zh-Hans/pages.article.list.json
Normal file
7
uni-app/src/app/locale/zh-Hans/pages.article.list.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"list": "文章列表",
|
||||||
|
"noData": "~ 暂无数据 ~",
|
||||||
|
"all": "全部",
|
||||||
|
"end": "-- 到底了 --",
|
||||||
|
"searchPlaceholder": "请输入搜索关键词"
|
||||||
|
}
|
||||||
11
uni-app/src/app/locale/zh-Hans/pages.auth.bind.json
Normal file
11
uni-app/src/app/locale/zh-Hans/pages.auth.bind.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"bindMobile": "绑定手机号",
|
||||||
|
"bind": "绑定",
|
||||||
|
"binding": "绑定中",
|
||||||
|
"agreeTips": "请阅读并同意",
|
||||||
|
"pleaceAgree": "请勾选已阅读并同意",
|
||||||
|
"mobilePlaceholder": "请输入手机号",
|
||||||
|
"codePlaceholder": "请输入验证码",
|
||||||
|
"weixinUserAuth": "一键绑定",
|
||||||
|
"mobileQuickLogin": "手机号快捷登录"
|
||||||
|
}
|
||||||
15
uni-app/src/app/locale/zh-Hans/pages.auth.login.json
Normal file
15
uni-app/src/app/locale/zh-Hans/pages.auth.login.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"logining": "登录中",
|
||||||
|
"usernamePlaceholder": "请输入账号",
|
||||||
|
"passwordPlaceholder": "请输入密码",
|
||||||
|
"resetpwd": "忘记密码",
|
||||||
|
"noAccount": "还没有账号",
|
||||||
|
"toRegister": "去注册",
|
||||||
|
"and": "和",
|
||||||
|
"agreeTips": "登录代表您同意",
|
||||||
|
"isAgreeTips": "请先阅读并同意协议",
|
||||||
|
"usernameLogin": "密码登录",
|
||||||
|
"mobileLogin": "验证码登录",
|
||||||
|
"mobilePlaceholder": "请输入手机号",
|
||||||
|
"oneClicklogin":"一键登录"
|
||||||
|
}
|
||||||
16
uni-app/src/app/locale/zh-Hans/pages.auth.register.json
Normal file
16
uni-app/src/app/locale/zh-Hans/pages.auth.register.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"registering": "注册中",
|
||||||
|
"usernamePlaceholder": "请输入账号",
|
||||||
|
"passwordPlaceholder": "请输入密码",
|
||||||
|
"confirmPasswordPlaceholder": "请再次确认密码",
|
||||||
|
"confirmPasswordError": "两次输入的密码不一致",
|
||||||
|
"resetpwd": "忘记密码",
|
||||||
|
"haveAccount": "已有账号",
|
||||||
|
"toLogin": "去登录",
|
||||||
|
"and": "和",
|
||||||
|
"registerAgreeTips": "注册代表您同意",
|
||||||
|
"isAgreeTips": "请先阅读并同意协议",
|
||||||
|
"usernameRegister": "账号注册",
|
||||||
|
"mobileRegister": "手机号注册",
|
||||||
|
"mobilePlaceholder": "请输入手机号"
|
||||||
|
}
|
||||||
6
uni-app/src/app/locale/zh-Hans/pages.auth.resetpwd.json
Normal file
6
uni-app/src/app/locale/zh-Hans/pages.auth.resetpwd.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"findPassword": "找回密码",
|
||||||
|
"passwordPlaceholder": "请输入密码",
|
||||||
|
"confirmPasswordPlaceholder": "请再次确认密码",
|
||||||
|
"confirmPasswordError": "两次输入的密码不一致"
|
||||||
|
}
|
||||||
10
uni-app/src/app/locale/zh-Hans/pages.index.develop.json
Normal file
10
uni-app/src/app/locale/zh-Hans/pages.index.develop.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"developTitle":"开发环境配置",
|
||||||
|
"baseUrl":"API请求地址",
|
||||||
|
"imgUrl":"图片服务器地址",
|
||||||
|
"siteId":"站点ID(VITE_SITE_ID)",
|
||||||
|
"siteIdPlaceholder": "请输入站点ID",
|
||||||
|
"pleaseEnterNumber":"请输入数字",
|
||||||
|
"maximumCannotExceed":"最大不能超过"
|
||||||
|
|
||||||
|
}
|
||||||
7
uni-app/src/app/locale/zh-Hans/pages.member.account.json
Normal file
7
uni-app/src/app/locale/zh-Hans/pages.member.account.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"alipayAccountNo": "支付宝账号",
|
||||||
|
"addBankCard": "添加银行卡",
|
||||||
|
"addAlipayAccount": "添加支付宝账号",
|
||||||
|
"endNumber": "尾号",
|
||||||
|
"bankCard": "银行卡"
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"addBankCard": "添加银行卡",
|
||||||
|
"addBankCardTips": "请添加持卡人本人的银行卡",
|
||||||
|
"addAlipayAccount": "添加支付宝账号",
|
||||||
|
"addAlipayAccountTips": "请添加已实名的支付宝账号",
|
||||||
|
"bankRealname": "持卡人姓名",
|
||||||
|
"bankRealnamePlaceholder": "请输入持卡人姓名",
|
||||||
|
"bankName": "银行名称",
|
||||||
|
"bankNamePlaceholder": "请输入银行名称",
|
||||||
|
"bankAccountNo": "银行卡号",
|
||||||
|
"bankAccountNoPlaceholder": "请输入银行卡号",
|
||||||
|
"alipayRealname": "真实姓名",
|
||||||
|
"alipayRealnamePlaceholder": "请输入真实姓名",
|
||||||
|
"alipayAccountNo": "支付宝账号",
|
||||||
|
"alipayAccountNoPlaceholder": "请输入支付宝账号",
|
||||||
|
"deleteConfirm": "确定要删除该账号吗?"
|
||||||
|
}
|
||||||
6
uni-app/src/app/locale/zh-Hans/pages.member.address.json
Normal file
6
uni-app/src/app/locale/zh-Hans/pages.member.address.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"address": "快递地址",
|
||||||
|
"locationAddress": "同城配送地址",
|
||||||
|
"createAddress": "新建收货地址",
|
||||||
|
"default": "默认"
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "收货人",
|
||||||
|
"namePlaceholder": "请输入收货人姓名",
|
||||||
|
"mobile": "手机号码",
|
||||||
|
"mobilePlaceholder": "请输入手机号码",
|
||||||
|
"selectArea":"选择地区",
|
||||||
|
"selectAreaPlaceholder":"请选择地区",
|
||||||
|
"address": "详细地址",
|
||||||
|
"addressPlaceholder": "请填写详细地址",
|
||||||
|
"defaultAddress": "设为默认地址",
|
||||||
|
"selectAddressPlaceholder":"请选择地址"
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"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": "添加"
|
||||||
|
}
|
||||||
15
uni-app/src/app/locale/zh-Hans/pages.member.balance.json
Normal file
15
uni-app/src/app/locale/zh-Hans/pages.member.balance.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"balanceInfo": "我的余额",
|
||||||
|
"recharge": "充值",
|
||||||
|
"cashOut":"提现",
|
||||||
|
"balanceDetail": "余额明细",
|
||||||
|
"accountBalance":"账户余额 (元)",
|
||||||
|
"balance":"余额 (元)",
|
||||||
|
"money":"可提现余额 (元)",
|
||||||
|
"availableBalance": "可用余额",
|
||||||
|
"rechargeAmountError": "充值金额错误",
|
||||||
|
"clickRecharge": "立即充值",
|
||||||
|
"rechargeAmountPlaceholder": "请输入充值金额",
|
||||||
|
"yuan":"元",
|
||||||
|
"rechargeRecord":"充值记录"
|
||||||
|
}
|
||||||
11
uni-app/src/app/locale/zh-Hans/pages.member.cash_out.json
Normal file
11
uni-app/src/app/locale/zh-Hans/pages.member.cash_out.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"applyTime": "申请时间",
|
||||||
|
"toBeReviewed": "官方正在审核,请耐心等待",
|
||||||
|
"toBeTransfer": "官方正在转账,请耐心等待",
|
||||||
|
"transfer": "官方已转账,请及时查收",
|
||||||
|
"cancelApply": "申请已取消",
|
||||||
|
"balanceDetail": "余额记录",
|
||||||
|
"commissionDetail": "佣金记录",
|
||||||
|
"emptyTip": "暂无提现记录",
|
||||||
|
"commissemptyTip": "暂无佣金记录"
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"statusName": "当前状态",
|
||||||
|
"cashOutNo": "交易号",
|
||||||
|
"serviceMoney": "手续费",
|
||||||
|
"createTime": "申请时间",
|
||||||
|
"auditTime": "审核时间",
|
||||||
|
"transferBank": "银行名称",
|
||||||
|
"transferAccount": "收款账号",
|
||||||
|
"refuseReason": "拒绝理由",
|
||||||
|
"transferTypeName": "转账方式名称",
|
||||||
|
"transferTime": "转账时间"
|
||||||
|
}
|
||||||
15
uni-app/src/app/locale/zh-Hans/pages.member.commission.json
Normal file
15
uni-app/src/app/locale/zh-Hans/pages.member.commission.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"recharge": "充值",
|
||||||
|
"cashOut":"提现",
|
||||||
|
"transferMoney":"提现",
|
||||||
|
"commissionDetail": "佣金明细",
|
||||||
|
"accountCommission":"当前佣金(元)",
|
||||||
|
"commission":"累计佣金(元)",
|
||||||
|
"money":"提现中佣金(元)",
|
||||||
|
"availableCommission": "可用佣金",
|
||||||
|
"rechargeAmountError": "充值金额错误",
|
||||||
|
"clickRecharge": "立即充值",
|
||||||
|
"rechargeAmountPlaceholder": "请输入充值金额",
|
||||||
|
"yuan":"元",
|
||||||
|
"commissionInfo": "我的佣金"
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"balanceDetail": "余额明细",
|
||||||
|
"commissionDetail": "佣金明细",
|
||||||
|
"balanceEmptyTip": "暂无余额明细",
|
||||||
|
"moneyEmptyTip": "暂无提现明细",
|
||||||
|
"commissionEmptyTip": "暂无佣金明细"
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "收货人",
|
||||||
|
"namePlaceholder": "请输入收货人姓名",
|
||||||
|
"mobile": "手机号码",
|
||||||
|
"mobilePlaceholder": "请输入手机号码",
|
||||||
|
"deliveryAddress":"收货地址",
|
||||||
|
"selectAddress":"选择地址",
|
||||||
|
"selectAddressPlaceholder":"请选择地址",
|
||||||
|
"address": "楼号门牌",
|
||||||
|
"addressPlaceholder": "详细地址如 1单元101",
|
||||||
|
"addressError": "请填写门牌号",
|
||||||
|
"defaultAddress": "设为默认地址",
|
||||||
|
"update": "修改"
|
||||||
|
}
|
||||||
12
uni-app/src/app/locale/zh-Hans/pages.member.personal.json
Normal file
12
uni-app/src/app/locale/zh-Hans/pages.member.personal.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"nickname": "昵称",
|
||||||
|
"sex": "性别",
|
||||||
|
"mobile": "手机号",
|
||||||
|
"birthday": "生日",
|
||||||
|
"unknown": "未知",
|
||||||
|
"updateHeadimg": "更换头像",
|
||||||
|
"updateNickname": "修改昵称",
|
||||||
|
"man": "男",
|
||||||
|
"woman": "女",
|
||||||
|
"bindMobile": "绑定手机"
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"rechargeRecord": "充值记录",
|
||||||
|
"emptyTip": "暂无充值记录"
|
||||||
|
}
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"orderNo": "订单编号",
|
||||||
|
"createTime": "创建时间"
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"recharge": "充值",
|
||||||
|
"cashOut":"提现",
|
||||||
|
"balanceDetail": "余额明细",
|
||||||
|
"accountBalance":"账户余额(元)",
|
||||||
|
"balance":"余额(元)",
|
||||||
|
"money":"可提现余额(元)",
|
||||||
|
"availableBalance": "可用余额",
|
||||||
|
"rechargeAmountError": "充值金额错误",
|
||||||
|
"clickRecharge": "立即充值",
|
||||||
|
"rechargeAmountPlaceholder": "请输入充值金额",
|
||||||
|
"yuan":"元"
|
||||||
|
}
|
||||||
6
uni-app/src/app/locale/zh-Hans/pages.setting.index.json
Normal file
6
uni-app/src/app/locale/zh-Hans/pages.setting.index.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"personalSettings": "个人设置",
|
||||||
|
"switchLang": "切换语言",
|
||||||
|
"version": "版本号",
|
||||||
|
"logout": "退出登录"
|
||||||
|
}
|
||||||
31
uni-app/src/app/pages/auth/agreement.vue
Normal file
31
uni-app/src/app/pages/auth/agreement.vue
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()" v-if="agreement">
|
||||||
|
<view v-if="agreement.content" class="p-[30rpx]">
|
||||||
|
<u-parse :content="agreement.content" :tagStyle="{img: 'vertical-align: top;'}"></u-parse>
|
||||||
|
</view>
|
||||||
|
<view v-else class="h-[100vh] w-full flex items-center justify-center">
|
||||||
|
<u-empty :icon="img('static/resource/images/empty.png')" text="暂无协议" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { getAgreementInfo } from '@/app/api/system'
|
||||||
|
import { img} from '@/utils/common'
|
||||||
|
|
||||||
|
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>
|
||||||
212
uni-app/src/app/pages/auth/bind.vue
Normal file
212
uni-app/src/app/pages/auth/bind.vue
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen flex flex-col" :style="themeColor()">
|
||||||
|
<view class="flex-1">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view class="h-[100rpx]"></view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="px-[60rpx] pt-[100rpx] mb-[100rpx]">
|
||||||
|
<view class="font-bold text-lg">{{ t('bindMobile') }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="px-[60rpx]">
|
||||||
|
<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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
|
||||||
|
<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 mt-[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="mt-[60rpx]">
|
||||||
|
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('binding')" @click="handleBind">{{t('bind')}}</button>
|
||||||
|
</view>
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<view class="mt-[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('mobileQuickLogin')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" @click="checkWxPrivacy" v-else></u-button>
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</u-form>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></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: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const 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 wxPrivacyPopupRef:any = ref(null)
|
||||||
|
|
||||||
|
// 检测是否同意隐私协议
|
||||||
|
const checkWxPrivacy = ()=>{
|
||||||
|
wxPrivacyPopupRef.value.proactive();
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
268
uni-app/src/app/pages/auth/login.vue
Normal file
268
uni-app/src/app/pages/auth/login.vue
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen flex flex-col" :style="themeColor()">
|
||||||
|
<view class="flex-1">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view class="h-[100rpx]"></view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="px-[60rpx] pt-[100rpx] mb-[100rpx]">
|
||||||
|
<view class="font-bold text-xl">{{ t('login') }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="px-[60rpx] text-sm flex mb-[50rpx] font-bold leading-none" 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="mx-[30rpx] border-solid border-0 border-r-[2px] border-gray-300" v-show="index == 0"></view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="px-[60rpx]">
|
||||||
|
<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" fontSize="26rpx" placeholderClass="!text-[#8288A2] text-[26rpx]"/>
|
||||||
|
</u-form-item>
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2] text-[26rpx]"/>
|
||||||
|
</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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
<view class="mt-[40rpx]">
|
||||||
|
<u-form-item label="" prop="mobile_code" :border-bottom="true">
|
||||||
|
<u-input v-model="formData.mobile_code" border="none" clearable class="!bg-transparent" fontSize="26rpx" :disabled="real_name_input" :placeholder="t('codePlaceholder')" placeholderClass="!text-[#8288A2]">
|
||||||
|
<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 mt-[20rpx] text-[#8288A2]">
|
||||||
|
<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="mt-[80rpx]">
|
||||||
|
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('logining')" @click="handleLogin">{{t('login')}}</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<view class="mt-[20rpx]" v-if="configStore.login.is_auth_register">
|
||||||
|
<button hover-class="none" class="text-[var(--primary-color)] bg-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loginLoading" :loadingText="t('logining')" @click="oneClickLogin">{{t('oneClicklogin')}}</button>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[20rpx]" v-else-if="type == 'mobile'">
|
||||||
|
<u-button :customStyle="{border:'none',color:'var(--primary-color)',fontSize:'26rpx',height:'40rpx', lineHeight:'40rpx'}" :text="t('mobileQuickLogin')" open-type="getPhoneNumber" @getphonenumber="mobileAuth" @click="checkWxPrivacy"></u-button>
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</u-form>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-xs py-[50rpx] flex justify-center w-full" v-if="configStore.login.agreement_show">
|
||||||
|
<text class="iconfont text-[var(--primary-color)] text-[34rpx] mr-[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>
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
|
import { usernameLogin, mobileLogin,bind } 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,getToken } from '@/utils/common'
|
||||||
|
import { onLoad,onShow } from '@dcloudio/uni-app';
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
mobile: '',
|
||||||
|
mobile_code: '',
|
||||||
|
mobile_key: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const real_name_input = ref(true);
|
||||||
|
onMounted(() => {
|
||||||
|
// 防止浏览器自动填充
|
||||||
|
setTimeout(()=>{
|
||||||
|
real_name_input.value = false;
|
||||||
|
},800)
|
||||||
|
});
|
||||||
|
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
|
onLoad(async()=>{
|
||||||
|
await configStore.getLoginConfig()
|
||||||
|
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') }))
|
||||||
|
if(!getToken() && !configStore.login.is_username && !configStore.login.is_mobile && !configStore.login.is_bind_mobile){
|
||||||
|
uni.showToast({ title: '商家未开启普通账号登录注册', icon: 'none' })
|
||||||
|
setTimeout(() => {
|
||||||
|
redirect({ url: '/app/pages/index/index', mode: 'reLaunch' })
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const type = ref('')
|
||||||
|
|
||||||
|
const loginType = computed(() => {
|
||||||
|
const value = []
|
||||||
|
if(configStore.login.is_username){
|
||||||
|
value.push({ type: 'username', title: t('usernameLogin') })
|
||||||
|
}
|
||||||
|
if(configStore.login.is_bind_mobile || 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)
|
||||||
|
if(configStore.login.is_bind_mobile && !res.data.mobile){
|
||||||
|
uni.setStorageSync('isbindmobile', true)
|
||||||
|
}
|
||||||
|
useLogin().handleLoginBack()
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo 一键登录
|
||||||
|
const loginLoading = ref(false)
|
||||||
|
const oneClickLogin = () =>{
|
||||||
|
// 第三方平台自动登录
|
||||||
|
if (loginLoading.value) return
|
||||||
|
loginLoading.value =true
|
||||||
|
const login = useLogin()
|
||||||
|
login.getAuthCode('',false,true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const wxPrivacyPopupRef:any = ref(null)
|
||||||
|
|
||||||
|
// 检测是否同意隐私协议
|
||||||
|
const checkWxPrivacy = ()=>{
|
||||||
|
wxPrivacyPopupRef.value.proactive();
|
||||||
|
}
|
||||||
|
const mobileAuth = (e) => {
|
||||||
|
if (!isAgree.value && configStore.login.agreement_show) {
|
||||||
|
uni.showToast({
|
||||||
|
title: `${ t('pleaceAgree') }《${ t('userAgreement') }》《${ t('privacyAgreement') }》`,
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const login = useLogin()
|
||||||
|
login.getAuthCode('',false,true,(data) => {
|
||||||
|
if (e.detail.errMsg == 'getPhoneNumber:ok') {
|
||||||
|
uni.showLoading({ title: '' })
|
||||||
|
|
||||||
|
bind({
|
||||||
|
openid:data.openid,
|
||||||
|
unionid:data.unionid,
|
||||||
|
mobile_code: e.detail.code
|
||||||
|
}).then((res) => {
|
||||||
|
uni.hideLoading()
|
||||||
|
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>
|
||||||
238
uni-app/src/app/pages/auth/register.vue
Normal file
238
uni-app/src/app/pages/auth/register.vue
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen flex flex-col" :style="themeColor()" >
|
||||||
|
<view class="flex-1">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view class="h-[100rpx]"></view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="px-[60rpx] pt-[100rpx] mb-[100rpx]">
|
||||||
|
<view class="font-bold text-xl">{{ t('register') }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="px-[60rpx] text-sm flex mb-[50rpx] font-bold leading-none" 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="mx-[30rpx] border-solid border-0 border-r-[2px] border-gray-300" v-show="index == 0"></view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="px-[60rpx]">
|
||||||
|
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
|
||||||
|
<view v-show="type == 'username'">
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-show="type == 'mobile' || configStore.login.is_bind_mobile">
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[30rpx]">
|
||||||
|
<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" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
|
||||||
|
<template #suffix>
|
||||||
|
<sms-code v-show="type" :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 class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
|
||||||
|
<template #suffix>
|
||||||
|
<image :src="captcha.image.value" class="h-[48rpx] w-[60rpx] ml-[20rpx]" mode="heightFix" @click="captcha.refresh()"></image>
|
||||||
|
</template>
|
||||||
|
</u-input>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex text-xs justify-between mt-[20rpx] text-[#8288A2]">
|
||||||
|
<view @click="redirect({ url: '/app/pages/auth/login' })">{{ t('haveAccount') }},<text class="text-primary">{{ t('toLogin') }}</text></view>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[80rpx]">
|
||||||
|
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('registering')" @click="handleRegister">{{t('register')}}</button>
|
||||||
|
</view>
|
||||||
|
</u-form>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-xs py-[50rpx] flex justify-center w-full" v-if="configStore.login.agreement_show">
|
||||||
|
<text class="iconfont text-[var(--primary-color)] text-[34rpx] mr-[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, getToken } from '@/utils/common'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app';
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
confirm_password: '',
|
||||||
|
mobile: '',
|
||||||
|
mobile_code: '',
|
||||||
|
mobile_key: '',
|
||||||
|
captcha_key: '',
|
||||||
|
captcha_code: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const real_name_input = ref(true);
|
||||||
|
onMounted(() => {
|
||||||
|
// 防止浏览器自动填充
|
||||||
|
setTimeout(()=>{
|
||||||
|
real_name_input.value = false;
|
||||||
|
},800)
|
||||||
|
});
|
||||||
|
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
const configStore = useConfigStore()
|
||||||
|
|
||||||
|
onLoad(async() =>{
|
||||||
|
await configStore.getLoginConfig()
|
||||||
|
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') }))
|
||||||
|
if(!getToken() && !configStore.login.is_username && !configStore.login.is_mobile && !configStore.login.is_bind_mobile){
|
||||||
|
uni.showToast({ title: '商家未开启普通账号登录注册', icon: 'none' })
|
||||||
|
setTimeout(() => {
|
||||||
|
redirect({ url: '/app/pages/index/index', mode: 'reLaunch' })
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const captcha = useCaptcha(formData)
|
||||||
|
captcha.refresh()
|
||||||
|
|
||||||
|
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>
|
||||||
134
uni-app/src/app/pages/auth/resetpwd.vue
Normal file
134
uni-app/src/app/pages/auth/resetpwd.vue
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen flex flex-col" :style="themeColor()">
|
||||||
|
<view class="flex-1">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view class="h-[100rpx]"></view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="px-[60rpx] pt-[100rpx] mb-[100rpx]">
|
||||||
|
<view class="font-bold text-xl">{{ t('findPassword') }}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="px-[60rpx]">
|
||||||
|
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]">
|
||||||
|
<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 class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[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" fontSize="26rpx" placeholderClass="!text-[#8288A2]"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[80rpx]">
|
||||||
|
<button hover-class="none" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :loading="loading" :loadingText="t('confirm')" @click="handleConfirm">{{t('confirm')}}</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: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const 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>
|
||||||
12
uni-app/src/app/pages/index/close.vue
Normal file
12
uni-app/src/app/pages/index/close.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen flex flex-col items-center justify-center" :style="themeColor()">
|
||||||
|
<u-empty :icon="img('static/resource/images/site/close.png')" :text="t('siteClose')"></u-empty>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { img } from '@/utils/common'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
61
uni-app/src/app/pages/index/develop.vue
Normal file
61
uni-app/src/app/pages/index/develop.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<view class="mt-[80rpx] px-[60rpx]" :style="themeColor()">
|
||||||
|
<view class="font-bold text-xl mb-[80rpx]">{{t('developTitle')}}</view>
|
||||||
|
<view class="mb-[40rpx] flex flex-col">
|
||||||
|
<text class="mb-[10rpx]">{{ t('baseUrl') }}</text>
|
||||||
|
<text class="text-sm">{{formData.baseUrl}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="mb-[40rpx] flex flex-col">
|
||||||
|
<text class="mb-[10rpx]">{{ t('imgUrl') }}</text>
|
||||||
|
<text class="text-sm">{{formData.imgUrl}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="mb-[40rpx] flex flex-col">
|
||||||
|
<text class="mb-[20rpx]">{{ t('siteId') }}</text>
|
||||||
|
<u-input v-model="formData.siteId" clearable :placeholder="t('siteIdPlaceholder')" />
|
||||||
|
</view>
|
||||||
|
<button class="mt-[80rpx] bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="save">{{t('confirm')}}</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import manifestJson from '@/manifest.json'
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
siteId: '',
|
||||||
|
baseUrl: import.meta.env.VITE_APP_BASE_URL || `${location.origin}/api/`,
|
||||||
|
imgUrl: import.meta.env.VITE_IMG_DOMAIN
|
||||||
|
})
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
if (formData.siteId.length == 0) {
|
||||||
|
uni.showToast({ title: t('siteIdPlaceholder'), icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var reg = /^[0-9]+$/;
|
||||||
|
if (!reg.test(formData.siteId)) {
|
||||||
|
uni.showToast({ title: t('pleaseEnterNumber'), icon: 'none' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (formData.siteId > 9999999) {
|
||||||
|
// uni.showToast({ title: t('maximumCannotExceed') + '9999999', icon: 'none' });
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
uni.setStorageSync('wap_site_id', formData.siteId);
|
||||||
|
|
||||||
|
let url = uni.getStorageSync('develop_before_path') || '/app/pages/index/index';
|
||||||
|
if (url == '/app/pages/index/develop') url = '/app/pages/index/index';
|
||||||
|
url = url.replace('/','')
|
||||||
|
|
||||||
|
uni.removeStorageSync('develop_before_path');
|
||||||
|
|
||||||
|
// 跳转到之前的页面
|
||||||
|
location.href = `${location.origin}${manifestJson.h5.router.base}${url}`
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
79
uni-app/src/app/pages/index/diy.vue
Normal file
79
uni-app/src/app/pages/index/diy.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
|
||||||
|
<u-loading-page :loading="diy.getLoading()" loadingText="" bg-color="#f7f7f7" />
|
||||||
|
|
||||||
|
<view v-show="!diy.getLoading()">
|
||||||
|
|
||||||
|
<!-- 自定义模板渲染 -->
|
||||||
|
<view class="diy-template-wrap bg-index" v-if="diy.data.pageMode != 'fixed'" :style="diy.pageStyle()">
|
||||||
|
|
||||||
|
<diy-group ref="diyGroupRef" :data="diy.data" :pullDownRefreshCount="diy.pullDownRefreshCount" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 固定模板渲染 -->
|
||||||
|
<view class="fixed-template-wrap" v-if="diy.data.pageMode == 'fixed'">
|
||||||
|
|
||||||
|
<fixed-group :data="diy.data" :pullDownRefreshCount="diy.pullDownRefreshCount" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref} from 'vue';
|
||||||
|
import {useDiy} from '@/hooks/useDiy'
|
||||||
|
import {useShare} from '@/hooks/useShare'
|
||||||
|
import diyGroup from '@/addon/components/diy/group/index.vue'
|
||||||
|
import fixedGroup from '@/addon/components/fixed/group/index.vue'
|
||||||
|
|
||||||
|
const {setShare} = useShare()
|
||||||
|
|
||||||
|
const diy = useDiy({})
|
||||||
|
|
||||||
|
const diyGroupRef = ref(null)
|
||||||
|
|
||||||
|
// 监听页面加载
|
||||||
|
diy.onLoad();
|
||||||
|
|
||||||
|
// 监听页面显示
|
||||||
|
diy.onShow((data: any) => {
|
||||||
|
let share = data.share ? JSON.parse(data.share) : null;
|
||||||
|
setShare(share);
|
||||||
|
diyGroupRef.value?.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听页面卸载
|
||||||
|
diy.onUnload();
|
||||||
|
|
||||||
|
// 监听下拉刷新事件
|
||||||
|
diy.onPullDownRefresh()
|
||||||
|
|
||||||
|
// 监听滚动事件
|
||||||
|
diy.onPageScroll()
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/styles/diy.scss';
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.diy-template-wrap {
|
||||||
|
/* #ifdef MP */
|
||||||
|
.child-diy-template-wrap {
|
||||||
|
::v-deep .diy-group {
|
||||||
|
> .draggable-element.top-fixed-diy {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
85
uni-app/src/app/pages/index/index.vue
Normal file
85
uni-app/src/app/pages/index/index.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
|
||||||
|
<u-loading-page :loading="diy.getLoading()" loadingText="" bg-color="#f7f7f7" />
|
||||||
|
|
||||||
|
<view v-show="!diy.getLoading()">
|
||||||
|
|
||||||
|
<!-- 自定义模板渲染 -->
|
||||||
|
<view class="diy-template-wrap bg-index" v-if="diy.data.pageMode != 'fixed'" :style="diy.pageStyle()">
|
||||||
|
|
||||||
|
<diy-group ref="diyGroupRef" :data="diy.data" :pullDownRefreshCount="diy.pullDownRefreshCount" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 固定模板渲染 -->
|
||||||
|
<view class="fixed-template-wrap" v-if="diy.data.pageMode == 'fixed'">
|
||||||
|
|
||||||
|
<fixed-group :data="diy.data" :pullDownRefreshCount="diy.pullDownRefreshCount" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref} from 'vue';
|
||||||
|
import {useDiy} from '@/hooks/useDiy'
|
||||||
|
import {redirect} from '@/utils/common';
|
||||||
|
import diyGroup from '@/addon/components/diy/group/index.vue'
|
||||||
|
import fixedGroup from '@/addon/components/fixed/group/index.vue'
|
||||||
|
|
||||||
|
const diy = useDiy({
|
||||||
|
name: 'DIY_INDEX'
|
||||||
|
})
|
||||||
|
|
||||||
|
const diyGroupRef = ref(null)
|
||||||
|
|
||||||
|
// 监听页面加载
|
||||||
|
diy.onLoad();
|
||||||
|
|
||||||
|
// 监听页面显示
|
||||||
|
diy.onShow((data: any) => {
|
||||||
|
if (data.value) {
|
||||||
|
// uni.setNavigationBarTitle({
|
||||||
|
// title: diyData.title
|
||||||
|
// })
|
||||||
|
} else if (data.page) {
|
||||||
|
// 跳转到设置的启动页
|
||||||
|
redirect({url: data.page, mode: 'reLaunch'})
|
||||||
|
}
|
||||||
|
diyGroupRef.value?.refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听页面卸载
|
||||||
|
diy.onUnload();
|
||||||
|
|
||||||
|
// 监听下拉刷新事件
|
||||||
|
diy.onPullDownRefresh()
|
||||||
|
|
||||||
|
// 监听滚动事件
|
||||||
|
diy.onPageScroll()
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/styles/diy.scss';
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.diy-template-wrap {
|
||||||
|
/* #ifdef MP */
|
||||||
|
.child-diy-template-wrap {
|
||||||
|
::v-deep .diy-group {
|
||||||
|
> .draggable-element.top-fixed-diy {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
12
uni-app/src/app/pages/index/nosite.vue
Normal file
12
uni-app/src/app/pages/index/nosite.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen flex flex-col items-center justify-center" :style="themeColor()">
|
||||||
|
<u-empty :icon="img('static/resource/images/site/close.png')" :text="t('noSite')"></u-empty>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { img } from '@/utils/common'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
104
uni-app/src/app/pages/member/account.vue
Normal file
104
uni-app/src/app/pages/member/account.vue
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen bg-page" :style="themeColor()">
|
||||||
|
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getCashoutAccountListFn">
|
||||||
|
<view class="h-[10rpx]"></view>
|
||||||
|
<u-swipe-action-item :options="accountOptions" @click="swipeClick(index)" v-for="(item, index) in accountList" :key="index" class="sidebar-marign my-[20rpx]">
|
||||||
|
<view class="p-[30rpx] bg-white rounded flex justify-between" >
|
||||||
|
<view class="flex">
|
||||||
|
<view class="w-[100rpx] h-[100rpx] flex items-center justify-center mr-[10rpx]" @click="handleClick(item)">
|
||||||
|
<image
|
||||||
|
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAACnVJREFUeF7tWXtQVNcZ/91FQQZZdhcXfKCCqFXQuKBV0YSHqWJ9AbU+qkZQG+uEyu66i0maB5jEaSetBdvG1vrCRhM1bQS1SUw6gn0kJhkDpqLNQ10jLApEHmrCuuyeznfWRZZd3L03/MOw38zOPfee8517vt/5fY9zV0AfF6GP2w8/AH4G9HEE/C7QxwngD4J+F/C7QB9HwO8CfZwA/iwgyQWuQznBBmGxAKGdwd4u41e0070Ndhtd7z2zUT+DYKN7GWzt14PDAtZOXfIjgLULYNaziuGfQ0A73QPMxtt2wdGG0H6vzwaB2kI7omyjoMZkMFgRav8MTGZFP+Eu7PZ23gaz8nGMWRHArGABVtht7QiQfY08Q2VXxosGwAzlVkDQAggR6z7bx87EjrEzcKtfkFhVIBjAcAYMZeJ1uYbwDWR4BnmG4s4TiALAjPBfAuwpKSvYFTsVBRPnSFF16ExigFKq8R2vvQmdMVwSAGYoVwHCq1IsqA4bjIXJOWgL6CdFHYhljt3vCWEsDfr8CudUPjOgFqpDArBMyhp2x07F899l96fbgQFS3uxBp/l2AAoL7aIBMEN1GUCMlGXkTsnE0agJUlSBgQCmdKxX2hz3tf4NnfER0S5QA4VGBplbBPV1NTNm58IUovR1uOu4IQC+10MACMJWaA3PigbADOV6QNgpxYKL8gg8Omu9FFWHzlg7MFS6uoumTJaOvE3vSgBAtRvAOinLeH2kBoaEBVJUHTqT7UCodHUXzf7BocjNvS0agFqoPhWAiQMy56HfpAmwXb2Gb0te5/MEps5EYMpMWMrehrXqv24r3ayZhwPRiZIsSNVEISV9mItuVUMDyi5/KX4+AR9Ba5zWVdFrFriOsBg7AigAYlBlBfprJuLb/YfQnJPL5wqvOMYBaExI9QjA7LSfgtKgFCktWIQMTSzONTZAERSEkaFyPs2a995ByYVqcVMK7DfQ5ueLBsAM5QpAOEiKQ9jXXL8p6zG0lb7F2/SMtbTiusI9QZiD5ZiSniduoZ1GN732BBTBQYjZtwum1lZUrVyNSYPU2PLhByg88764ee1sETblH5cAgIpKRy1RPbz8GNe/oRwFe3MLZwOxoq3sbTRlruJ9MkUY7yM5NiwOh9bkISU+CvvLL8BU39rtohUhjvKYrjROE6NG5W9X4eqtVkTv3cUZULliNaLlciS89iqqGurFAWBlkcjPd1Py6gJ1UL3PgKQQ3QbIi7bCeu48GjUp/OXOZ636Z/g99dtMXyEgegQH4bllzyJi41pER8iR87uT3Kh9G9P5ffMdC9Kee4MbfPSpRR3G03Plqh3QLUxE0doUvvOll75AZuwYbvz+i9WoqLmGouQ0mFpb0GyxICYsDJnHy3B0QQYHjNhB7e1VnziYwnAOeqPGE2IPBOAmlGFtEIj3AYqSVxCcvdzF/5WlBzAg44fc/wkM6r+95WUMLNjM3/WDec9gd8mT3GAy6srOdWj5xgLdngpu9PYTlRyIgmXTeTtzWixGquUQsopQYkhH9sNx3CACodnShtJLX/J2+eKlHAiS7PHxvE0xgZ6frq0BY4yDojn4Fw4QGH4PvdGjLz4QgBoo58sgnKAXOYPdne070ar7Bad6ZNNlnhHqozUdAbJOCOdxof1qDZKKTuHj4tU4XV2DklMXsG/jHGw5fIZT3NlOnRDFXSTmZ3tQ/uISKAcGQbFyB67sWYdolTvdSxdmIGPUaO4GmbGjUTAtCfp/VqC48iyY1tCxyS6BUmDLoM0/IpoBZihfAgTOb+duE7UtpW/x9EdUp4B4t+I/HAxyDwKHYsWVwyfwQn1gh6E0B+10yalqaGIiEBMph0Z/gPu5IIC3iSEEFrkLZ4vFAsWf/uCy7oofL0PKsChknSjjbtA5JjgBIBak/vXwfT1mjYH+aZMEAFRUNc0mRTI2tPBJbjiJteo87hT/kRtPwVBevJW3qRYgd3jzZCU+mzQFtMOFhz5A1ZUGlD69iO922UeX+DOif8VLS1D64SUOTPG6VM4UU30LCh9PQtXNeuhOl7usOycuHsXJaWi+a+FpsTNIzizhGiSFi9AZ4rqLmA90ATNUzQDCxIVbx+iVST9BeWSsFFWAEkKSuPqfmHBlzeM8HuS8+06n9wo7oTNsEA3ADaiSbIDIZHv/NXHzDGgOpM84EkTNgHhx53+K+mlRwxG9b5cj8DmFCWugN5SIBqAOKiMDfi1h+ahSDMG81O6PDuTflBmKj3+Cc6ZGnh61CxK4K1AmcAr5OUX+pg0/548o7WnUES5LIrpTcVQyZ67nAokFxEGvvygaADNUbwLIkgJAd5+/KOdTpKcASDGBhHyegiOlx+LjlRipDkXO3Hgog4N4AKRIT7vrzP/7Zs/l+Z0kZ3w8qhod8xA4rtTnjy9DZ3ygH3YbA8xQ1QBwPYn4iMb6qYtxYuh4t9G061QIVZy/1tF3ztTAawK6UlAk4ZXjPV8uTkmDVpPIix+qBokBlPYyRrna1XLXwoshF2HYD70x50HL9giAGeHjANYtbbzh8P30jagNdo+dBEBJXrpLaUysIPoTIwgAhTwImhFqpP3tCDeaAhulSdpd2n2HoaWIlofxe2cf+b2H8jgXOuMO0QDUQrVOAOgbgGgxhagwY/YTHvVyZsVzY8nnnf5P91T8EP0zpsZi/6fVyJgWy098ZGTlisc4EFQBUgokZjhPhalRw3nAI8OJFW4ACJgCrfGsaADqoNrLgDWirQdwZMRD0CU6avuu4qzvie4U8JwVYeeS2NTUihabhZexuoTJKEpO5UYTGFQAUdAjV6C4QFdnGUzGu0R/oBY6Y5Q3G7pxAdX/6EucN2VP/fma+TgYneBRlYoiCoL6vac5A4gRVBJn/eoYrw4pGAovb+N1ABlHtT35PFV1hdNn8DYdjQkYnSaRF0NNbW0cFA/yBnTGpd5scAPgOgZG2BF4w5tid/2pj27A56GDPHYXLk/iRtLOUzVI/p+d5ijSiBWTotW8Tf5PhQ35eFchV6A+chFyAToMdfOBxAidcZs3O9wAMCM8C2CUAkVLc/9gxM2/fyDpOgEZTP5PQiBQ0HPeUxDUJKqBkYz7fGdxRn9KdeQKTr93PvdAf8BuT8amzf/yZoQHAFSE2iZvip763xs8FtnTvbKu+6nHMGCYuArQ82RCA4beisLSwrve7HADoBaqMwLg9vHQ20TUvzV+Fl4ZM8OXoZ7H9NQXYIa/Q2/06VO0CwAM6FcHlVWqBRmPZOPj8OHS1GUAksUdgLp9kSA8D63hRV8W4gLANShSAyBzPX/6Msu9MUMzXf50EaFJHwMZoOkJ+vPXzoXOeNKXBXRlQGCd4wgs6Ri3Kmk5TkWO9uW97mOIAQ/bAbp+N9kGndHo6xSegqDkf4G2jUsG/STLODsg7S8EQIAZEP4MrWGLmPd7LIS+AIIGQJEkZqLOYwseSudfYL8KCav/R+QYs6h51BiMMAxGsKwRKjsdyHyTTv/5+6bgGOX1s7iYyXrjWD8AvXHXenLNfgb0JJq9cS4/A3rjrvXkmv0M6Ek0e+Ncfgb0xl3ryTX7GdCTaPbGufo8A/4PpckqfWjPHTQAAAAASUVORK5CYII="
|
||||||
|
mode="widthFix" class="w-[80rpx]" v-if="item.account_type == 'bank'"></image>
|
||||||
|
<text class="iconfont iconzhifubaoxuanzhong text-[#188dfb] text-[80rpx]" v-else></text>
|
||||||
|
</view>
|
||||||
|
<view @click="handleClick(item)">
|
||||||
|
<view>{{ item.account_type == 'bank' ? item.bank_name : t('alipayAccountNo') }}</view>
|
||||||
|
<view v-if="item.account_type == 'bank'" class="text-sm text-gray-subtitle mt-[10rpx]">{{ t('endNumber') }} {{ item.account_no.substring(item.account_no.length - 4) }}{{ t('bankCard') }}</view>
|
||||||
|
<view v-else class="text-sm text-gray-subtitle mt-[10rpx]">{{ item.account_no }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<text class="flex items-center nc-iconfont nc-icon-xiugaiV6xx shrink-0 text-[32rpx] p-[20rpx] pr-0" @click="editAccount(item)"></text>
|
||||||
|
</view>
|
||||||
|
</u-swipe-action-item>
|
||||||
|
<view class="p-[30rpx] bg-white sidebar-marign my-[20rpx] rounded flex" @click="redirect({ url: '/app/pages/member/account_edit', param: { type: accountType, mode } })">
|
||||||
|
<u-icon name="plus" color="#333" size="16"></u-icon>
|
||||||
|
<text class="text-sm ml-[10rpx] flex-1">{{ accountType == 'bank' ? t('addBankCard') : t('addAlipayAccount') }}</text>
|
||||||
|
<u-icon name="arrow-right" color="#333" size="14"></u-icon>
|
||||||
|
</view>
|
||||||
|
</mescroll-body>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { redirect } from '@/utils/common'
|
||||||
|
import { getCashoutAccountList, deleteCashoutAccount } from '@/app/api/member'
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue'
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js'
|
||||||
|
import { onPageScroll, onReachBottom, onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
|
||||||
|
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||||
|
const accountList = ref<Array<any>>([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const accountType = ref('bank')
|
||||||
|
const mescrollRef = ref(null)
|
||||||
|
const mode = ref('get')
|
||||||
|
|
||||||
|
onLoad((data: any) => {
|
||||||
|
data.type && (accountType.value = data.type)
|
||||||
|
data.mode && (mode.value = data.mode)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getCashoutAccountListFn = (mescroll : mescrollStructure) => {
|
||||||
|
loading.value = false;
|
||||||
|
let data : object = {
|
||||||
|
page: mescroll.num,
|
||||||
|
limit: mescroll.size,
|
||||||
|
account_type: accountType.value
|
||||||
|
};
|
||||||
|
|
||||||
|
getCashoutAccountList(data).then((res) => {
|
||||||
|
const newArr = (res.data.data as Array<Object>);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1) {
|
||||||
|
accountList.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
accountList.value = accountList.value.concat(newArr);
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
loading.value = true;
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = true;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const editAccount = (item: any)=> {
|
||||||
|
const url = `/app/pages/member/account_edit`
|
||||||
|
redirect({ url, param: { id : item.account_id, type : item.account_type, mode:mode.value} })
|
||||||
|
}
|
||||||
|
|
||||||
|
const accountOptions = ref([
|
||||||
|
{
|
||||||
|
text: t('delete'),
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#F56C6C'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const swipeClick = (index: any) => {
|
||||||
|
const data = accountList.value[index]
|
||||||
|
deleteCashoutAccount(data.account_id).then(() => {
|
||||||
|
accountList.value.splice(index, 1)
|
||||||
|
}).catch()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (data: AnyObject) => {
|
||||||
|
if (mode.value == 'get') redirect({ url: '/app/pages/member/account_edit', param: { id: data.account_id, type: accountType.value, mode: mode.value }, mode: 'redirectTo' })
|
||||||
|
else redirect({ url: '/app/pages/member/apply_cash_out', param: { account_id: data.account_id, type: accountType.value }, mode: 'redirectTo'})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
142
uni-app/src/app/pages/member/account_edit.vue
Normal file
142
uni-app/src/app/pages/member/account_edit.vue
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<scroll-view scroll-y="true" class="w-screen h-screen bg-page">
|
||||||
|
<view class="h-[20rpx]"></view>
|
||||||
|
<view class="p-[30rpx] bg-white sidebar-marign rounded">
|
||||||
|
<block v-if="formData.account_type == 'bank'">
|
||||||
|
<view class="text-center text-base font-bold mt-[50rpx]">{{ t('addBankCard') }}</view>
|
||||||
|
<view class="text-center text-sm mt-[10rpx]">{{ t('addBankCardTips') }}</view>
|
||||||
|
|
||||||
|
<view class="mt-[50rpx]">
|
||||||
|
<u-form labelPosition="left" :model="formData" :label-style="{'font-size':'28rpx'}" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('bankRealname')" prop="realname" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.realname" fontSize="28rpx" maxlength="30" border="none" clearable :placeholder="t('bankRealnamePlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('bankName')" prop="bank_name" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.bank_name" fontSize="28rpx" maxlength="30" border="none" clearable :placeholder="t('bankNamePlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('bankAccountNo')" prop="account_no" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.account_no" fontSize="28rpx" maxlength="30" border="none" clearable :placeholder="t('bankAccountNoPlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
</u-form>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<block v-if="formData.account_type == 'alipay'">
|
||||||
|
<view class="text-center text-base font-bold mt-[50rpx]">{{ t('addAlipayAccount') }}</view>
|
||||||
|
<view class="text-center text-sm mt-[10rpx]">{{ t('addAlipayAccountTips') }}</view>
|
||||||
|
|
||||||
|
<view class="mt-[50rpx]">
|
||||||
|
<u-form labelPosition="left" :model="formData" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('alipayRealname')" prop="realname" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.realname" maxlength="30" border="none" clearable :placeholder="t('alipayRealnamePlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('alipayAccountNo')" prop="account_no" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.account_no" border="none" maxlength="30" clearable :placeholder="t('alipayAccountNoPlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
</u-form>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
|
||||||
|
<view class="mt-[100rpx]">
|
||||||
|
<button :loading="loading" class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="handleSave">{{t('save')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<u-modal :show="deleteConfirm" :content="t('deleteConfirm')" :confirmText="t('confirm')" :cancelText="t('cancel')" :showCancelButton="true" @confirm="handleDelete" @cancel="deleteConfirm = false" confirmColor="var(--primary-color)"></u-modal>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, reactive } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { getCashoutAccountInfo, addCashoutAccount, editCashoutAccount, deleteCashoutAccount } from '@/app/api/member'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { redirect } from '@/utils/common'
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const formRef = ref(null)
|
||||||
|
const mode = ref('get')
|
||||||
|
const deleteConfirm = ref(false)
|
||||||
|
const formData = reactive<AnyObject>({
|
||||||
|
account_id: 0,
|
||||||
|
account_type: 'bank',
|
||||||
|
bank_name: '',
|
||||||
|
realname: '',
|
||||||
|
account_no: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
'realname': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: formData.account_type == 'bank' ? t('bankRealnamePlaceholder') : t('alipayRealnamePlaceholder'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
'bank_name': {
|
||||||
|
type: 'string',
|
||||||
|
required: formData.account_type == 'bank',
|
||||||
|
message: t('bankNamePlaceholder'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
'account_no': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: formData.account_type == 'bank' ? t('bankAccountNoPlaceholder') : t('alipayAccountNoPlaceholder'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onLoad((data: any) => {
|
||||||
|
data.type && (formData.account_type = data.type)
|
||||||
|
data.mode && (mode.value = data.mode)
|
||||||
|
if (data.id) {
|
||||||
|
formData.account_id = data.id
|
||||||
|
|
||||||
|
getCashoutAccountInfo({ account_id: data.id }).then((res : any) => {
|
||||||
|
if (res.data) {
|
||||||
|
Object.keys(formData).forEach((key : string) => {
|
||||||
|
if (res.data[key] != undefined) formData[key] = res.data[key]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
const save = formData.account_id ? editCashoutAccount : addCashoutAccount
|
||||||
|
|
||||||
|
formRef.value.validate().then(() => {
|
||||||
|
if (loading.value) return
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
save(formData).then((res) => {
|
||||||
|
if (mode.value == 'get') redirect({ url: '/app/pages/member/account', param: { type: formData.account_type, mode: mode.value } })
|
||||||
|
else redirect({ url: '/app/pages/member/apply_cash_out', param: { account_id: formData.account_id ? formData.account_id : res.data.id, type: formData.account_type } , mode: 'redirectTo'})
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDelete = () => {
|
||||||
|
deleteCashoutAccount(formData.account_id).then(() => {
|
||||||
|
redirect({ url: '/app/pages/member/account', mode: 'redirectTo' })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
158
uni-app/src/app/pages/member/address.vue
Normal file
158
uni-app/src/app/pages/member/address.vue
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<view class="address bg-[var(--page-bg-color)] min-h-[100vh]" v-if="!loading" :style="themeColor()">
|
||||||
|
<scroll-view scroll-y="true">
|
||||||
|
<view class="sidebar-margin pt-[var(--top-m)]" v-if="addressList.length">
|
||||||
|
<view class="mb-[var(--top-m)] rounded-[var(--rounded-big)] overflow-hidden" v-for="(item, index) in addressList">
|
||||||
|
<view class="flex flex-col card-template">
|
||||||
|
<view class="flex-1 line-feed mr-[20rpx]" @click="selectAddress(item)">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="text-[#333] text-[30rpx] leading-[34rpx] font-500">{{ item.name }}</view>
|
||||||
|
<text class="text-[#333] text-[30rpx] ml-[10rpx]">{{ mobileHide(item.mobile) }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[16rpx] text-[26rpx] line-feed text-[var(--text-color-light9)] leading-[1.4]">{{ item.full_address }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-between pt-[26rpx]">
|
||||||
|
<view class="flex items-center text-[28rpx] leading-none" @click.stop="setDefault(index)">
|
||||||
|
<text class="iconfont !text-[28rpx] mr-[10rpx]" :class="{ 'iconduigou text-primary': item.is_default, 'iconcheckbox_nol': !item.is_default }"></text>
|
||||||
|
设为默认
|
||||||
|
</view>
|
||||||
|
<view class="flex">
|
||||||
|
<view class="text-[28rpx]" @click.stop="editAddressFn(item.id)"><text class="nc-iconfont nc-icon-xiugaiV6xx shrink-0 text-[28rpx] mr-[4rpx]"></text>编辑</view>
|
||||||
|
<view @click.stop="deleteAddressFn(index)" class="ml-[40rpx] text-[28rpx]"><text class="nc-iconfont nc-icon-shanchu-yuangaizhiV6xx shrink-0 text-[28rpx] mr-[4rpx]"></text>删除</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-empty v-if="!addressList.length" :option="{tip : '暂无收货地址'}"></mescroll-empty>
|
||||||
|
<view class="w-full footer">
|
||||||
|
<view class="py-[var(--top-m)] px-[var(--sidebar-m)] footer w-full fixed bottom-0 left-0 right-0 box-border">
|
||||||
|
<button hover-class="none" class="primary-btn-bg text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[26rpx] font-500" @click="addAddress">{{t('createAddress')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { onLoad,onShow } from '@dcloudio/uni-app'
|
||||||
|
import { redirect, img, mobileHide } from '@/utils/common'
|
||||||
|
import { getAddressList, deleteAddress, editAddress } from '@/app/api/member'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const current = ref(0)
|
||||||
|
const addressList = ref<object[]>([])
|
||||||
|
const locationAddressList = ref<object[]>([])
|
||||||
|
const type = ref('')
|
||||||
|
const source = ref('')
|
||||||
|
|
||||||
|
onLoad((data: any) => {
|
||||||
|
type.value = data.type || ''
|
||||||
|
source.value = data.source || ''
|
||||||
|
if (data.type) current.value = data.type == 'address' ? 0 : 1
|
||||||
|
// 清空缓存,防止受待支付界面影响
|
||||||
|
if(uni.getStorageSync('selectAddressCallback')){uni.removeStorage({ key: 'selectAddressCallback' })}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getAddressListFn = () => {
|
||||||
|
getAddressList({}).then(({ data }) => {
|
||||||
|
const address: any = [], locationAddress: any = []
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
item.type == 'address' ? address.push(item) : locationAddress.push(item)
|
||||||
|
})
|
||||||
|
if(!source.value){ //地址管理使用
|
||||||
|
addressList.value = data;
|
||||||
|
}else{ // 区分同城配送地址和快递地址
|
||||||
|
addressList.value = current.value == 0 ? address : locationAddress;
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onShow(()=>{
|
||||||
|
getAddressListFn()
|
||||||
|
})
|
||||||
|
|
||||||
|
const addAddress = ()=> {
|
||||||
|
const url = `/app/pages/member/address_edit`
|
||||||
|
redirect({ url, param: { source : source.value } })
|
||||||
|
}
|
||||||
|
|
||||||
|
const editAddressFn = (id: number)=> {
|
||||||
|
const url = `/app/pages/member/address_edit`
|
||||||
|
redirect({ url, param: { id, source : source.value} })
|
||||||
|
}
|
||||||
|
|
||||||
|
const addressOptions = ref([
|
||||||
|
{
|
||||||
|
text: t('delete'),
|
||||||
|
style: {
|
||||||
|
backgroundColor: '#F56C6C'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const selectAddress = (data: any) => {
|
||||||
|
const selectAddress = uni.getStorageSync('selectAddressCallback')
|
||||||
|
if (selectAddress) {
|
||||||
|
selectAddress.address_id = data.id
|
||||||
|
|
||||||
|
uni.setStorage({
|
||||||
|
key: 'selectAddressCallback',
|
||||||
|
data: selectAddress,
|
||||||
|
success() {
|
||||||
|
redirect({url: selectAddress.back, mode: 'redirectTo'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAddressFn = (index: any) => {
|
||||||
|
const data: any = addressList.value[index]
|
||||||
|
|
||||||
|
deleteAddress(data.id).then(() => {
|
||||||
|
addressList.value.splice(index, 1)
|
||||||
|
}).catch()
|
||||||
|
}
|
||||||
|
|
||||||
|
const setDefault = (index: any) => {
|
||||||
|
const data: any = addressList.value[index]
|
||||||
|
if (data.is_default) return
|
||||||
|
|
||||||
|
data.is_default = 1;
|
||||||
|
editAddress(data).then(() => {
|
||||||
|
addressList.value.forEach((item, itemIndex) => {
|
||||||
|
item.is_default && (item.is_default = 0)
|
||||||
|
itemIndex == index && (item.is_default = 1)
|
||||||
|
})
|
||||||
|
}).catch()
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.u-tabs__wrapper__nav__line) {
|
||||||
|
bottom: 0;
|
||||||
|
background: var(--primary-color) !important;
|
||||||
|
}
|
||||||
|
.line-feed{
|
||||||
|
word-wrap:break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
:deep(.u-swipe-action-item__right__button__wrapper__text.u-line-1){
|
||||||
|
font-size: 24rpx !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
:deep(.u-swipe-action-item__right__button__wrapper){
|
||||||
|
padding:0 10rpx !important;
|
||||||
|
}
|
||||||
|
.footer{
|
||||||
|
height: calc(80rpx + var(--top-m) + var(--top-m) + constant(safe-area-inset-bottom)) !important;
|
||||||
|
height: calc(80rpx + var(--top-m) + var(--top-m) + env(safe-area-inset-bottom)) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
333
uni-app/src/app/pages/member/address_edit.vue
Normal file
333
uni-app/src/app/pages/member/address_edit.vue
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<template>
|
||||||
|
<view class="bg-[var(--page-bg-color)] min-h-[100vh] overflow-hidden address-edit" :style="themeColor()">
|
||||||
|
<u-form labelPosition="left" :model="formData" errorType='toast' :rules="rules" ref="formRef">
|
||||||
|
<view class="sidebar-margin card-template mt-[var(--top-m)] py-[20rpx]">
|
||||||
|
<view class="">
|
||||||
|
<u-form-item :label="t('name')" prop="name" labelWidth="200rpx">
|
||||||
|
<u-input fontSize="28rpx" v-model.trim="formData.name" border="none" clearable maxlength="25" placeholderStyle="color: #888" :placeholder="t('namePlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[16rpx]">
|
||||||
|
<u-form-item :label="t('mobile')" prop="mobile" labelWidth="200rpx">
|
||||||
|
<u-input fontSize="28rpx" v-model.trim="formData.mobile" maxlength="11" border="none" clearable :placeholder="t('mobilePlaceholder')" placeholderStyle="color: #888"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[16rpx]">
|
||||||
|
<u-form-item :label="t('selectArea')" prop="area" labelWidth="200rpx">
|
||||||
|
<view class="flex w-full items-center h-[52rpx]" v-if="addressType == 'address' && isSelectMap != 1" @click="selectArea">
|
||||||
|
<view v-if="!formData.area" class="text-[#888] text-[28rpx] flex-1">{{ t('selectAreaPlaceholder') }}</view>
|
||||||
|
<view v-else class="text-[28rpx] flex-1 leading-[1.4]">{{ formData.area }}</view>
|
||||||
|
<view @click.stop="chooseLocation" class="flex items-center">
|
||||||
|
<text class="nc-iconfont nc-icon-dizhiguanliV6xx mr-[4rpx] text-[32rpx] text-[#e93323]"></text>
|
||||||
|
<text class="text-[24rpx] whitespace-nowrap text-[#e93323]">定位</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else class="flex justify-between items-center flex-1 h-[52rpx]" @click="chooseLocation">
|
||||||
|
<view class="text-[28rpx] text-[#303133] leading-[1.4]" v-if="formData.area || formData.address_name">{{formData.area || formData.address_name}}</view>
|
||||||
|
<view class="text-[#888] text-[28rpx]" v-else>{{t('selectAddressPlaceholder')}}</view>
|
||||||
|
<view class="flex items-center">
|
||||||
|
<text class="nc-iconfont nc-icon-dizhiguanliV6xx text-[32rpx] mr-[4rpx] text-[#e93323]"></text>
|
||||||
|
<text class="text-[24rpx] whitespace-nowrap text-[#e93323]">定位</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[16rpx]">
|
||||||
|
<u-form-item :label="t('address')" prop="address" labelWidth="200rpx">
|
||||||
|
<u-input fontSize="28rpx" v-model="formData.address" border="none" clearable maxlength="120" :placeholder="t('addressPlaceholder')" placeholderStyle="color: #888"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="sidebar-margin card-template mt-[var(--top-m)] py-[10rpx]">
|
||||||
|
<u-form-item :label="t('defaultAddress')" prop="name" :border-bottom="false" labelWidth="200rpx">
|
||||||
|
<u-switch v-model="formData.is_default" size="20" :activeValue="1" :inactiveValue="0" activeColor="var(--primary-color)" inactiveColor="var(--temp-bg)"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
</u-form>
|
||||||
|
<view class="w-full footer">
|
||||||
|
<view class="py-[var(--top-m)] px-[var(--sidebar-m)] footer w-full fixed bottom-0 left-0 right-0 box-border">
|
||||||
|
<button hover-class="none" class="primary-btn-bg !text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[26rpx] font-500"
|
||||||
|
@click="save" :disabled="btnDisabled" :loading="operateLoading" :class="{'opacity-50': btnDisabled}">{{t('save')}}</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<area-select ref="areaRef" @complete="areaSelectComplete" :area-id="formData.district_id"/>
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed,nextTick } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { redirect } from '@/utils/common'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { addAddress, editAddress, getAddressInfo } from '@/app/api/member'
|
||||||
|
import manifestJson from '@/manifest.json'
|
||||||
|
import { getAddressByLatlng } from '@/app/api/system'
|
||||||
|
|
||||||
|
const formData: any = ref({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
mobile: '',
|
||||||
|
province_id: 0,
|
||||||
|
city_id: 0,
|
||||||
|
district_id: 0,
|
||||||
|
lat: '',
|
||||||
|
lng: '',
|
||||||
|
address: '',
|
||||||
|
address_name: '',
|
||||||
|
full_address: '',
|
||||||
|
is_default: 0,
|
||||||
|
area: ''
|
||||||
|
})
|
||||||
|
const areaRef = ref()
|
||||||
|
const formRef: any = ref(null)
|
||||||
|
const source = ref('')
|
||||||
|
const btnDisabled = ref(false)
|
||||||
|
const isSelectAddress = ref(false)
|
||||||
|
const addressType = ref('address');
|
||||||
|
const isSelectMap = ref(2) // 值为1,该地址需要有经纬度,反之不需要
|
||||||
|
|
||||||
|
const wxPrivacyPopupRef:any = ref(null)
|
||||||
|
|
||||||
|
onLoad((data: any) => {
|
||||||
|
isSelectMap.value = data.isSelectMap || '';
|
||||||
|
const selectAddress = uni.getStorageSync('selectAddressCallback')
|
||||||
|
if (data.id) {
|
||||||
|
getAddressInfo(data.id).then((res: any) => {
|
||||||
|
res.data && Object.assign(formData.value, res.data)
|
||||||
|
// 兼容待支付页面编辑地址
|
||||||
|
if (selectAddress) {
|
||||||
|
addressType.value = selectAddress.delivery == 'express' ? 'address' : 'locationAddress';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} else if (data.name) {
|
||||||
|
if (uni.getStorageSync('addressInfo')) {
|
||||||
|
Object.assign(formData.value, uni.getStorageSync('addressInfo'))
|
||||||
|
}
|
||||||
|
formData.value.address = data.name;
|
||||||
|
getAddress(data.latng);
|
||||||
|
var tempArr = getQueryVariable('latng').split(',');
|
||||||
|
formData.value.lat = tempArr[0];
|
||||||
|
formData.value.lng = tempArr[1];
|
||||||
|
}
|
||||||
|
source.value = data.source || ''
|
||||||
|
if (selectAddress) {
|
||||||
|
addressType.value = selectAddress.delivery == 'express' ? 'address' : 'locationAddress';
|
||||||
|
}
|
||||||
|
// #ifdef MP
|
||||||
|
nextTick(() => {
|
||||||
|
if (wxPrivacyPopupRef.value) wxPrivacyPopupRef.value.proactive();
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
'name': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: t('namePlaceholder'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
'mobile': [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: t('mobilePlaceholder'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator(rule: any, value: any, callback: any) {
|
||||||
|
let mobile = /^1[3-9]\d{9}$/;
|
||||||
|
if (!mobile.test(value)){
|
||||||
|
callback(new Error(t('mobileError')))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'area': {
|
||||||
|
validator() {
|
||||||
|
let bool = true;
|
||||||
|
if(uni.$u.test.isEmpty(formData.value.area) && uni.$u.test.isEmpty(formData.value.address_name)){
|
||||||
|
bool = false;
|
||||||
|
}
|
||||||
|
return bool
|
||||||
|
},
|
||||||
|
message: t('selectAreaPlaceholder')
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: t('addressPlaceholder'),
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectArea = () => {
|
||||||
|
isSelectAddress.value = true
|
||||||
|
areaRef.value.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
const areaSelectComplete = (event: any) => {
|
||||||
|
if(isSelectAddress.value && (formData.value.province_id == event.province.id || formData.value.city_id != event.city.id || formData.value.district_id != event.district.id)){
|
||||||
|
formData.value.lat = '';
|
||||||
|
formData.value.lng = '';
|
||||||
|
}
|
||||||
|
formData.value.province_id = event.province.id || 0
|
||||||
|
formData.value.city_id = event.city.id || 0
|
||||||
|
formData.value.district_id = event.district.id || 0
|
||||||
|
formData.value.area = `${event.province.name || ''}${event.city.name || ''}${event.district.name || ''}`
|
||||||
|
isSelectAddress.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const operateLoading = ref(false)
|
||||||
|
const save = ()=> {
|
||||||
|
const save = formData.value.id ? editAddress : addAddress
|
||||||
|
formRef.value.validate().then(() => {
|
||||||
|
if (operateLoading.value) return
|
||||||
|
operateLoading.value = true
|
||||||
|
|
||||||
|
btnDisabled.value = true
|
||||||
|
|
||||||
|
formData.value.full_address = formData.value.area + formData.value.address
|
||||||
|
|
||||||
|
if(isSelectMap.value == 1 && !formData.value.lat && !formData.value.lng){
|
||||||
|
uni.showToast({
|
||||||
|
title: '缺少经纬度,请在地图上重新选点',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
operateLoading.value = false;
|
||||||
|
btnDisabled.value = false
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
save(formData.value).then((res: any) => {
|
||||||
|
operateLoading.value = false
|
||||||
|
setTimeout(() => {
|
||||||
|
btnDisabled.value = false
|
||||||
|
if(source.value == 'shop_order_payment'){
|
||||||
|
const selectAddress = uni.getStorageSync('selectAddressCallback')
|
||||||
|
if (selectAddress) {
|
||||||
|
selectAddress.address_id = res.data.id || formData.value.id
|
||||||
|
uni.setStorage({
|
||||||
|
key: 'selectAddressCallback',
|
||||||
|
data: selectAddress,
|
||||||
|
success() {
|
||||||
|
redirect({url: selectAddress.back, mode: 'redirectTo'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
redirect({
|
||||||
|
url: '/app/pages/member/address',
|
||||||
|
mode: 'redirectTo',
|
||||||
|
param: {source: source.value}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}).catch(() => {
|
||||||
|
operateLoading.value = false
|
||||||
|
btnDisabled.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择地址
|
||||||
|
const chooseLocation = ()=> {
|
||||||
|
// #ifdef MP
|
||||||
|
uni.chooseLocation({
|
||||||
|
success: (res) => {
|
||||||
|
res.latitude && (formData.value.lat = res.latitude)
|
||||||
|
res.longitude && (formData.value.lng = res.longitude)
|
||||||
|
res.address && (formData.value.area = res.address)
|
||||||
|
res.name && (formData.value.address_name = res.address)
|
||||||
|
res.name && (formData.value.address = res.name)
|
||||||
|
if (res.latitude && res.longitude) {
|
||||||
|
let latng = res.latitude + ',' + res.longitude;
|
||||||
|
getAddress(latng);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: (res)=>{
|
||||||
|
// 在隐私协议中没有声明chooseLocation:fail api作用域
|
||||||
|
if(res.errMsg && res.errno) {
|
||||||
|
if(res.errno == 104){
|
||||||
|
let msg = '用户未授权隐私权限,选择位置失败';
|
||||||
|
uni.showToast({title: msg, icon: 'none'})
|
||||||
|
}else if(res.errno == 112){
|
||||||
|
let msg = '隐私协议中未声明,打开地图选择位置失败';
|
||||||
|
uni.showToast({title: msg, icon: 'none'})
|
||||||
|
}else {
|
||||||
|
uni.showToast({title: res.errMsg, icon: 'none'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
var urlencode = formData.value;
|
||||||
|
uni.setStorageSync('addressInfo', urlencode);
|
||||||
|
let backurl = location.origin + location.pathname + '?source=' + source.value;
|
||||||
|
if(isSelectMap.value){
|
||||||
|
backurl = backurl + '&isSelectMap=' + isSelectMap.value
|
||||||
|
}
|
||||||
|
window.location.href = 'https://apis.map.qq.com/tools/locpicker?search=1&type=0&backurl=' + encodeURIComponent(backurl) + '&key=' + manifestJson.h5.sdkConfigs.maps.qqmap.key + '&referer=myapp';
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取详细地址
|
||||||
|
const getAddress = (latlng:any)=> {
|
||||||
|
getAddressByLatlng({latlng}).then((res: any) => {
|
||||||
|
if (res.data) {
|
||||||
|
formData.value.full_address = '';
|
||||||
|
formData.value.full_address += res.data.province != undefined ? res.data.province : '';
|
||||||
|
formData.value.full_address += res.data.city != undefined ? '' + res.data.city : '';
|
||||||
|
formData.value.full_address += res.data.district != undefined ? '' + res.data.district : '';
|
||||||
|
|
||||||
|
formData.value.address_name = formData.value.full_address.replace(/-/g,'');
|
||||||
|
formData.value.area = (res.data.province + res.data.city + res.data.district) || res.data.full_address;
|
||||||
|
|
||||||
|
formData.value.province_id = res.data.province_id != undefined ? res.data.province_id : 0;
|
||||||
|
formData.value.city_id = res.data.city_id != undefined ? res.data.city_id : 0;
|
||||||
|
formData.value.district_id = res.data.district_id != undefined ? res.data.district_id : 0;
|
||||||
|
} else {
|
||||||
|
uni.showToast({title: res.msg, icon: 'none'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const getQueryVariable = (variable:any)=> {
|
||||||
|
var query = window.location.search.substring(1);
|
||||||
|
var vars = query.split('&');
|
||||||
|
for (var i = 0; i < vars.length; i++) {
|
||||||
|
var pair = vars[i].split('=');
|
||||||
|
if (pair[0] == variable) {
|
||||||
|
return pair[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.address-edit :deep(.u-form-item__body__left__content__label){
|
||||||
|
font-size: 28rpx !important;
|
||||||
|
}
|
||||||
|
.address-edit :deep(.u-form-item__body__right){
|
||||||
|
display:flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.footer{
|
||||||
|
height: calc(100rpx + var(--top-m) + var(--top-m) + constant(safe-area-inset-bottom)) !important;
|
||||||
|
height: calc(100rpx + var(--top-m) + var(--top-m) + env(safe-area-inset-bottom)) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
320
uni-app/src/app/pages/member/apply_cash_out.vue
Normal file
320
uni-app/src/app/pages/member/apply_cash_out.vue
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<scroll-view :scroll-y="true" class="w-screen h-screen bg-page" v-if="!pageLoading && config.is_open == 1">
|
||||||
|
<view class="sidebar-marign pt-[20rpx]">
|
||||||
|
<view class="card-template">
|
||||||
|
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx]">{{t('cashOutMoneyTip')}}</view>
|
||||||
|
<view class="flex pt-[30rpx] pb-[8rpx] items-center border-0 border-b-[2rpx] border-solid border-[#F1F2F5]">
|
||||||
|
<text class="text-[54rpx] font-500 leading-[76rpx] ">{{ t('currency') }}</text>
|
||||||
|
<input type="digit" class="h-[76rpx] leading-[76rpx] pl-[10rpx] flex-1 font-bold text-[54rpx] bg-[#fff]" v-model="applyData.apply_money" maxlength="7" :placeholder="applyData.apply_money?'':(t('minWithdrawal') + t('currency') + moneyFormat(config.min))" placeholder-class="apply-price" :adjust-position="false"/>
|
||||||
|
<image @click="clearMoney" v-if="applyData.apply_money"
|
||||||
|
:src="img('static/resource/images/member/apply_withdrawal/close.png')" class="w-[40rpx] h-[40rpx]"
|
||||||
|
mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="pt-[20rpx] flex items-center justify-between">
|
||||||
|
<view class="text-[26rpx] text-[#626779] leading-[36rpx]">
|
||||||
|
<text>{{t('money')}}:{{ t('currency') }}{{ moneyFormat(cashOutMoney) }}</text>
|
||||||
|
<text>,{{t('commissionTo')}}{{ config.rate + '%' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="text-[26rpx] text-primary leading-[36rpx]" @click="allMoney">{{t('allTx')}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="mt-[20rpx] card-template">
|
||||||
|
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx] mb-[30rpx]">到账方式</view>
|
||||||
|
<!-- 提现到微信 -->
|
||||||
|
<view class="p-[20rpx] mb-[20rpx] flex items-center rounded-[16rpx] border-[1rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('wechatpay') && memberStore.info && (memberStore.info.wx_openid || memberStore.info.weapp_openid)" @click="applyData.transfer_type = 'wechatpay'" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'wechatpay'}">
|
||||||
|
<view>
|
||||||
|
<image class="h-[60rpx] w-[60rpx]" :src="img('static/resource/images/member/apply_withdrawal/wechat.png')" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="flex-1 px-[20rpx]">
|
||||||
|
<view class="text-[28rpx] text-[#333] leading-[40rpx] mb-[6rpx]">{{ t('cashOutToWechat') }}</view>
|
||||||
|
<view class="text-[#999] text-[24rpx] leading-[34rpx]">{{ t('cashOutToWechatTips') }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 提现到支付宝 -->
|
||||||
|
<view class="p-[20rpx] mb-[20rpx] flex items-center rounded-[16rpx] border-[1rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('alipay')" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'alipay' && alipayAccountInfo}" >
|
||||||
|
<view @click="transferAlipay" >
|
||||||
|
<image class="h-[60rpx] w-[60rpx] align-middle" :src="img('static/resource/images/member/apply_withdrawal/alipay-icon.png')" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="flex-1 px-[22rpx]" @click="transferAlipay" >
|
||||||
|
<view class="text-[28rpx] text-[#333] leading-[40rpx] mb-[6rpx]">{{ t('cashOutToAlipay') }}</view>
|
||||||
|
<view class="text-[#999] text-[24rpx] leading-[34rpx]">
|
||||||
|
<view v-if="alipayAccountInfo" class="truncate max-w-[440rpx]">
|
||||||
|
<text>{{ t('cashOutTo') }}{{ t('alipayAccountNo') }}</text>
|
||||||
|
<text class="text-[#333]">{{ alipayAccountInfo.account_no }}</text>
|
||||||
|
</view>
|
||||||
|
<view v-else>{{ t('cashOutToAlipayTips') }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center">
|
||||||
|
<u-button :plain="true" :text="t('toAdd')" type="primary" shape="circle" :custom-style="{height: '54rpx'}" v-if="!alipayAccountInfo && !alipayLoading" @click="redirect({ url: '/app/pages/member/account', param: { type: 'alipay', mode: 'select' } , mode: 'redirectTo'})"></u-button>
|
||||||
|
<text v-else class="nc-iconfont nc-icon-youV6xx text-[40rpx] text-[#999] p-[10rpx]" @click.stop="redirect({ url: '/app/pages/member/account', param: { type: 'alipay', mode: 'select' } , mode: 'redirectTo'})"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 提现到银行卡 -->
|
||||||
|
<view class="p-[20rpx] flex items-center rounded-[16rpx] border-[1rpx] border-solid border-[#eee]" v-if="config.transfer_type.includes('bank')" :class="{'border-[#089C98] bg-[#F6FFFF]': applyData.transfer_type == 'bank' && bankAccountInfo}">
|
||||||
|
<view @click="transferBank" >
|
||||||
|
<image class="h-[42rpx] w-[60rpx] align-middle" :src="img('static/resource/images/member/apply_withdrawal/bank-icon.png')" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
<view class="flex-1 px-[20rpx]" @click="transferBank" >
|
||||||
|
<view class="text-[28rpx] text-[#333] leading-[40rpx] mb-[6rpx]">{{ t('cashOutToBank') }}</view>
|
||||||
|
<view class="text-[#999] text-[24rpx] leading-[34rpx]">
|
||||||
|
<view v-if="bankAccountInfo" class="truncate max-w-[440rpx]">
|
||||||
|
<text>{{ t('cashOutTo') }}{{ bankAccountInfo.bank_name }}{{ t('debitCard') }}</text>
|
||||||
|
<text class="text-[#333]">{{ bankAccountInfo.account_no.substring(bankAccountInfo.account_no.length - 4) }} </text>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
{{ t('cashOutToBankTips') }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center">
|
||||||
|
<button hover-class="none" class="h-[54rpx] leading-[50rpx] rounded-full p-[0] w-[100rpx] text-[var(--primary-color)] bg-transparent border-[2rpx] border-solid border-[var(--primary-color)] text-[28rpx]" v-if="!bankAccountInfo && !bankLoading" @click="redirect({ url: '/app/pages/member/account', param: { type: 'bank', mode: 'select' }, mode: 'redirectTo' })">{{t('toAdd')}}</button>
|
||||||
|
<text v-else class="nc-iconfont nc-icon-youV6xx text-[40rpx] text-[#999] p-[10rpx]" @click.stop="redirect({ url: '/app/pages/member/account', param: { type: 'bank', mode: 'select' }, mode: 'redirectTo' })"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="fixed bottom-[60rpx] left-0 right-0 px-[30rpx]">
|
||||||
|
<button class="mt-[100rpx] h-[80rpx] !text-[#fff] leading-[80rpx] primary-btn-bg rounded-[50rpx] text-[32rpx]" :disabled="applyData.apply_money == '' || applyData.apply_money == 0" :loading="loading" @click="cashOut">{{t('cashOutNow')}}</button>
|
||||||
|
<view class="mt-[20rpx] text-center text-[26rpx] text-primary" @click.stop="redirect({ url: '/app/pages/member/cash_out'})">
|
||||||
|
{{t('cashOutList')}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="h-[100vh] w-[100vw] flex justify-center items-center" v-if="config.is_open == 0 && !pageLoading">
|
||||||
|
<u-empty :text="t('isOpenApply')" width="320rpx" height="244rpx" :icon="img('static/resource/images/empty.png')"/>
|
||||||
|
</view>
|
||||||
|
<u-loading-page :loading="pageLoading" bg-color="#e8e8e8" loading-text=""></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, reactive, watch, computed } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { moneyFormat, redirect, getToken ,img, deepClone } from '@/utils/common'
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import { cashOutConfig, cashOutApply, getFirstCashoutAccountInfo, getCashoutAccountInfo } from '@/app/api/member'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
const pageLoading = ref(true)
|
||||||
|
const loading = ref(false)
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
|
||||||
|
// 申请提现数据
|
||||||
|
const applyData = reactive({
|
||||||
|
apply_money: '',
|
||||||
|
transfer_type: '',
|
||||||
|
account_type: 'money',
|
||||||
|
account_id: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 可提现金额
|
||||||
|
const cashOutMoney = computed(() => {
|
||||||
|
return memberStore.info ? memberStore.info[ applyData.account_type ] : 0
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => applyData.transfer_type, (nval) => {
|
||||||
|
switch (nval) {
|
||||||
|
case 'bank':
|
||||||
|
applyData.account_id = bankAccountInfo.value ? bankAccountInfo.value.account_id : 0
|
||||||
|
break;
|
||||||
|
case 'alipay':
|
||||||
|
applyData.account_id = alipayAccountInfo.value ? alipayAccountInfo.value.account_id : 0
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
applyData.account_id = 0
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
const config = reactive<AnyObject>({
|
||||||
|
is_auto_transfer: 0, // 是否自动转账
|
||||||
|
is_auto_verify: 0, // 是否自动审核
|
||||||
|
is_open: 0, // 是否启用提现
|
||||||
|
min: 0, // 最低提现金额
|
||||||
|
rate: 0, // 手续费比率
|
||||||
|
transfer_type: [] // 提现方式
|
||||||
|
})
|
||||||
|
|
||||||
|
let query:AnyObject | undefined = {}
|
||||||
|
|
||||||
|
onLoad(async (data) => {
|
||||||
|
query = data
|
||||||
|
|
||||||
|
uni.getStorageSync('cashOutAccountType') && (applyData.account_type = uni.getStorageSync('cashOutAccountType'))
|
||||||
|
|
||||||
|
if(getToken()){
|
||||||
|
memberStore.getMemberInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!['money', 'commission'].includes(applyData.account_type)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('abnormalOperation'),
|
||||||
|
icon: 'none',
|
||||||
|
success() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if(getCurrentPages().length > 1){
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
redirect({
|
||||||
|
url: '/app/pages/member/index',
|
||||||
|
mode: 'reLaunch'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提现配置
|
||||||
|
await cashOutConfig().then((res : any) => {
|
||||||
|
for (let key in deepClone(res.data)) {
|
||||||
|
config[key] = deepClone(res.data[key]);
|
||||||
|
}
|
||||||
|
if (config.transfer_type.includes('wechatpay') && memberStore.info && (!memberStore.info.wx_openid && !memberStore.info.weapp_openid)) config.transfer_type.splice(config.transfer_type.indexOf('wechatpay'),1)
|
||||||
|
config.transfer_type.includes('bank') && getBankAccountInfo()
|
||||||
|
config.transfer_type.includes('alipay') && getAlipayAccountInfo()
|
||||||
|
applyData.transfer_type = config.transfer_type[0]
|
||||||
|
if(query.type){
|
||||||
|
applyData.transfer_type = query.type
|
||||||
|
}
|
||||||
|
pageLoading.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//全部提现
|
||||||
|
const allMoney = () => {
|
||||||
|
if(parseFloat(cashOutMoney.value)) applyData.apply_money = moneyFormat(cashOutMoney.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空提现金额
|
||||||
|
const clearMoney = () => {
|
||||||
|
applyData.apply_money = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const verify = () => {
|
||||||
|
if (!applyData.transfer_type) {
|
||||||
|
uni.showToast({ title: t('noAvailableCashOutType'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (uni.$u.test.isEmpty(applyData.apply_money)) {
|
||||||
|
uni.showToast({ title: t('applyMoneyPlaceholder'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!uni.$u.test.amount(applyData.apply_money)) {
|
||||||
|
uni.showToast({ title: t('moneyformatError'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (parseFloat(applyData.apply_money) > parseFloat(cashOutMoney.value)) {
|
||||||
|
uni.showToast({ title: t('applyMoneyExceed'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (parseFloat(applyData.apply_money) < parseFloat(config.min)) {
|
||||||
|
uni.showToast({ title: t('applyMoneyBelow'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取支付宝提现账号信息
|
||||||
|
*/
|
||||||
|
const alipayLoading = ref(false)
|
||||||
|
const alipayAccountInfo:any = ref(null)
|
||||||
|
const getAlipayAccountInfo = () => {
|
||||||
|
const data = { account_type: 'alipay', account_id: 0 }
|
||||||
|
let request = getFirstCashoutAccountInfo
|
||||||
|
|
||||||
|
if (query.type && query.type == 'alipay' && query.account_id) {
|
||||||
|
request = getCashoutAccountInfo
|
||||||
|
data.account_id = query.account_id
|
||||||
|
}
|
||||||
|
alipayLoading.value = true
|
||||||
|
request(data).then(res => {
|
||||||
|
if (res.data && res.data.account_id) {
|
||||||
|
alipayAccountInfo.value = res.data
|
||||||
|
// 初始化赋值
|
||||||
|
if(applyData.transfer_type == 'alipay' && !applyData.account_id){
|
||||||
|
applyData.account_id = alipayAccountInfo.value.account_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alipayLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取银行卡提现账号信息
|
||||||
|
*/
|
||||||
|
const bankLoading = ref(false)
|
||||||
|
const bankAccountInfo = ref(null)
|
||||||
|
const getBankAccountInfo = () => {
|
||||||
|
const data = { account_type: 'bank', account_id: 0 }
|
||||||
|
let request = getFirstCashoutAccountInfo
|
||||||
|
|
||||||
|
if (query.type && query.type == 'bank' && query.account_id) {
|
||||||
|
request = getCashoutAccountInfo
|
||||||
|
data.account_id = query.account_id
|
||||||
|
}
|
||||||
|
bankLoading.value = true
|
||||||
|
request(data).then(res => {
|
||||||
|
if (res.data && res.data.account_id) {
|
||||||
|
bankAccountInfo.value = res.data
|
||||||
|
// 初始化赋值
|
||||||
|
if(applyData.transfer_type == 'bank' && !applyData.account_id){
|
||||||
|
applyData.account_id = bankAccountInfo.value.account_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bankLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请提现
|
||||||
|
*/
|
||||||
|
const cashOut = ()=> {
|
||||||
|
if (verify()) {
|
||||||
|
if (loading.value) return
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
cashOutApply(applyData).then(res => {
|
||||||
|
loading.value = false
|
||||||
|
redirect({ url: '/app/pages/member/cash_out' })
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选中提现到支付宝
|
||||||
|
const transferAlipay = () => {
|
||||||
|
if(!alipayAccountInfo.value){
|
||||||
|
uni.showToast({ title: t('cashOutToAlipayTips'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
applyData.transfer_type = 'alipay'
|
||||||
|
}
|
||||||
|
// 选中提现到银行卡
|
||||||
|
const transferBank = () => {
|
||||||
|
if(!bankAccountInfo.value){
|
||||||
|
uni.showToast({ title: t('cashOutToBankTips'), icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
applyData.transfer_type = 'bank'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.apply-price){
|
||||||
|
color: #8288A2;
|
||||||
|
font-size: 26rpx;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 76rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
253
uni-app/src/app/pages/member/balance.vue
Normal file
253
uni-app/src/app/pages/member/balance.vue
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
<template>
|
||||||
|
<view class="min-h-[100vh] !bg-[#F6F6F6]" :style="themeColor()" v-if="memberStore.info">
|
||||||
|
<view class="fixed w-full z-2 !bg-[#F6F6F6]">
|
||||||
|
<view class="pb-[203rpx] text-[#fff] w-full" :style="headerStyle">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<top-tabbar :data="param" class="top-header"/>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="leading-[39rpx] text-[28rpx] pl-[53rpx] pt-[79rpx]">{{t('accountBalance')}}</view>
|
||||||
|
<view class="flex items-baseline pl-[53rpx]">
|
||||||
|
<text class="text-[40rpx] leading-[56rpx]">¥</text>
|
||||||
|
<text class="text-[70rpx] leading-[98rpx]">{{ memberStore.info ? moneyFormat((parseFloat(memberStore.info.balance) + parseFloat(memberStore.info.money)).toString()) : '0.00' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="sidebar-marign py-[30rpx] bg-[#fff] rounded-[16rpx] px-[40rpx] box-border w-[calc(100% - 60rpx)] mt-[-112rpx]">
|
||||||
|
<view class="flex flex-col items-center w-full" @click="redirect({ url: '/app/pages/member/detailed_account', param: { type : 'money' } })" :class="{'pt-[12rpx]': !Object.keys(cashOutConfigObj).length || (Object.keys(cashOutConfigObj).length && !systemStore.siteAddons.includes('recharge') && cashOutConfigObj.is_open != 1)}">
|
||||||
|
<view class=" text-[#999] text-[24rpx] leading-[34rpx] font-400">{{t('money')}}</view>
|
||||||
|
<view class="flex items-baseline text-[#333]">
|
||||||
|
<text class="text-[26rpx] leading-[36rpx]">¥</text>
|
||||||
|
<text class="text-[44rpx] leading-[62rpx] font-bold">{{ moneyFormat(memberStore.info?.money)|| '0.00' }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<view class="mt-[50rpx] flex justify-between" v-if="Object.keys(cashOutConfigObj).length && (systemStore.siteAddons.includes('recharge') || cashOutConfigObj.is_open == 1)">
|
||||||
|
<button :class="{'!w-[630rpx]': cashOutConfigObj.is_open != 1}" class="w-[280rpx] h-[66rpx] rounded-[40rpx] text-[30rpx] !bg-[#fff] !text-[var(--primary-color)] leading-[64rpx] !m-0 border-[2rpx] border-[var(--primary-color)] border-solid box-border" shape="circle" v-if="systemStore.siteAddons.includes('recharge')"
|
||||||
|
@click="redirect({url: '/addon/recharge/pages/recharge'})">充值</button>
|
||||||
|
<view v-if="cashOutConfigObj.is_open == 1" :class="{'!w-[630rpx]': !systemStore.siteAddons.includes('recharge')}" class="text-center w-[280rpx] h-[66rpx] rounded-[40rpx] text-[30rpx] !text-[#fff] leading-[66rpx] !m-0"
|
||||||
|
style="background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;" @click="applyCashOut">{{t('cashOut')}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="px-[var(--sidebar-m)] box-border mt-[20rpx] flex justify-between items-center">
|
||||||
|
<scroll-view :scroll-x="true" scroll-with-animation :scroll-into-view="'id' + (subActive>3 ? subActive - 2 : 0)" class="!h-[100%] flex-1">
|
||||||
|
<view class="flex whitespace-nowrap">
|
||||||
|
<view :id="'id' + index" class="text-[26rpx] leading-[70rpx] text-[#666] font-400" :class="{ 'class-select': fromType === item.key,'ml-30rpx':index}" @click="fromTypeFn(item.key,index)" v-for="(item, index) in accountTypeList">{{ item.name }}</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<view class="flex items-center" @click="handleSelect">
|
||||||
|
<view class="text-[26rpx] text-[#333] mr-[10rpx]">日期</view>
|
||||||
|
<view class="nc-iconfont nc-icon-riliV6xx !text-[28rpx] leading-[36rpx]"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" height="auto" @up="getListFn" :top="mescrollTop">
|
||||||
|
<view class="sidebar-marign pt-[20rpx] body-bottom" v-if="list.length">
|
||||||
|
<view v-for="(item,index) in list" :key="item.id" class="w-full h-[120rpx] flex justify-between items-center bg-[#fff] box-border p-[20rpx] rounded-[16rpx]" :class="{'mt-[20rpx]':index>0}">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="w-[80rpx] h-[80rpx] text-center rounded-[40rpx] text-[40rpx] font-bold leading-[80rpx] text-[#fff]"
|
||||||
|
:class="{'bg-[#EF000C]' :item.account_data > 0&&item.account_type!='money', 'bg-[#03B521]':item.account_data <= 0&&item.account_type!='money','bg-[#1379FF]':item.account_type=='money'}">
|
||||||
|
{{item.account_type=='money'?'提':item.account_data > 0?'收':'支'}}
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-col ml-[20rpx]">
|
||||||
|
<view class="text-[#000] text-[26rpx] leading-[36rpx]">{{item.from_type_name}}</view>
|
||||||
|
<view class="text-[#999] text-[24rpx] leading-[34rpx] mt-[4rpx] font-400">{{item.create_time}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-right">
|
||||||
|
<view class="text-[36rpx] leading-[50rpx]"
|
||||||
|
:class="{'text-[#EF000C]' :item.account_data > 0&&item.account_type!='money', 'text-[#03B521]':item.account_data <= 0&&item.account_type!='money'}">{{ item.account_data > 0 ? '+' + item.account_data : item.account_data }}</view>
|
||||||
|
<view class="text-[#999] text-[24rpx] leading-[34rpx] mt-[4rpx] font-400">
|
||||||
|
<text class="mr-[15rpx]">剩余余额</text>
|
||||||
|
<text>{{item.account_sum}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="box-border pt-[20rpx] px-[30rpx] body-bottom" :style="{'height':'calc(100vh - '+mescrollTop +')'}" v-if="!list.length && !loading &&!listLoading">
|
||||||
|
<view class="h-full rounded-[16rpx] flex items-center justify-center">
|
||||||
|
<mescroll-empty></mescroll-empty>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</mescroll-body>
|
||||||
|
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
|
||||||
|
<!-- <pay ref="payRef" @close="rechargeLoading = false"></pay> -->
|
||||||
|
<!-- 时间选择 -->
|
||||||
|
<select-date ref="selectDateRef" @confirm="confirmFn" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive,computed } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { moneyFormat, redirect, img,pxToRpx } from '@/utils/common';
|
||||||
|
import { cashOutConfig,getBalanceListAll } from '@/app/api/member';
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
|
||||||
|
import { onShow, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import useSystemStore from '@/stores/system'
|
||||||
|
import { topTabar } from '@/utils/topTabbar'
|
||||||
|
import selectDate from '@/components/select-date/select-date.vue';
|
||||||
|
|
||||||
|
const { downCallback,mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
const systemStore = useSystemStore()
|
||||||
|
|
||||||
|
/********* 自定义头部 - start ***********/
|
||||||
|
const topTabarObj = topTabar()
|
||||||
|
let param = topTabarObj.setTopTabbarParam({title:'我的余额'})
|
||||||
|
/********* 自定义头部 - end ***********/
|
||||||
|
|
||||||
|
const cashOutConfigObj = reactive({})
|
||||||
|
onShow(() => {
|
||||||
|
cashOutConfig().then((res) => {
|
||||||
|
for (let key in res.data) {
|
||||||
|
cashOutConfigObj[key] = res.data[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取系统状态栏的高度
|
||||||
|
let menuButtonInfo:any = {};
|
||||||
|
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
|
||||||
|
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||||
|
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
|
||||||
|
// #endif
|
||||||
|
const headerStyle = computed(()=>{
|
||||||
|
return {
|
||||||
|
backgroundImage: 'url(' + img('static/resource/images/member/balance_bg.png') + ') ',
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'bottom',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const mescrollTop = computed(()=>{
|
||||||
|
if(Object.keys(cashOutConfigObj).length && (systemStore.siteAddons.includes('recharge') || cashOutConfigObj.is_open == 1)){
|
||||||
|
if(Object.keys(menuButtonInfo).length){
|
||||||
|
return (pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) +pxToRpx(8)+669)+'rpx'
|
||||||
|
}else{
|
||||||
|
return '669rpx'
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(Object.keys(menuButtonInfo).length){
|
||||||
|
return (pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) +pxToRpx(8)+566)+'rpx'
|
||||||
|
}else{
|
||||||
|
return '566rpx'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//获取数据来源类型
|
||||||
|
const accountTypeList = ref([
|
||||||
|
{name:'全部',key:''},
|
||||||
|
{name:'收入',key:'income'},
|
||||||
|
{name:'支出',key:'disburse'},
|
||||||
|
{name:'提现',key:'cash_out'},
|
||||||
|
])
|
||||||
|
const fromType = ref('')
|
||||||
|
const create_time = ref([])
|
||||||
|
//来源类型
|
||||||
|
const subActive = ref(0)
|
||||||
|
const fromTypeFn = (key,index)=>{
|
||||||
|
fromType.value = key
|
||||||
|
subActive.value = index
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyCashOut = () => {
|
||||||
|
uni.setStorageSync('cashOutAccountType', 'money')
|
||||||
|
redirect({ url: '/app/pages/member/apply_cash_out' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const list = ref<Array<any>>([]),
|
||||||
|
loading = ref<boolean>(true),
|
||||||
|
listLoading = ref<boolean>(true),
|
||||||
|
mescrollRef = ref(null);
|
||||||
|
|
||||||
|
interface mescrollStructure {
|
||||||
|
num : number,
|
||||||
|
size : number,
|
||||||
|
endSuccess : Function,
|
||||||
|
[propName : string] : any
|
||||||
|
}
|
||||||
|
|
||||||
|
const getListFn = (mescroll : mescrollStructure) => {
|
||||||
|
listLoading.value = true;
|
||||||
|
let data : Object = {
|
||||||
|
page: mescroll.num,
|
||||||
|
limit: mescroll.size,
|
||||||
|
trade_type:fromType.value,
|
||||||
|
create_time: create_time.value
|
||||||
|
|
||||||
|
};
|
||||||
|
interface acceptingDataStructure {
|
||||||
|
data : acceptingDataItemStructure,
|
||||||
|
msg : string,
|
||||||
|
code : number
|
||||||
|
}
|
||||||
|
interface acceptingDataItemStructure {
|
||||||
|
data : [],
|
||||||
|
[propName : string] : number | string | object
|
||||||
|
}
|
||||||
|
|
||||||
|
getBalanceListAll(data).then((res : acceptingDataStructure) => {
|
||||||
|
let newArr = res.data.data;
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1) {
|
||||||
|
list.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
list.value = list.value.concat(newArr);
|
||||||
|
listLoading.value = false;
|
||||||
|
loading.value = false;
|
||||||
|
}).catch(() => {
|
||||||
|
listLoading.value = false;
|
||||||
|
loading.value = false;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//日期筛选
|
||||||
|
const selectDateRef = ref()
|
||||||
|
const handleSelect = () =>{
|
||||||
|
selectDateRef.value.show = true
|
||||||
|
}
|
||||||
|
// 确定时间筛选
|
||||||
|
const confirmFn = (data) =>{
|
||||||
|
create_time.value = data;
|
||||||
|
list.value = []
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.class-select {
|
||||||
|
position: relative;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--primary-color);
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 4rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
width: 40rpx;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:deep(.uni-scroll-view){
|
||||||
|
overflow: auto hidden !important;
|
||||||
|
}
|
||||||
|
.body-bottom{
|
||||||
|
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
|
||||||
|
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
.pl-20rpx{
|
||||||
|
padding-left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
75
uni-app/src/app/pages/member/cash_out.vue
Normal file
75
uni-app/src/app/pages/member/cash_out.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<view class="member-record-list" :style="themeColor()">
|
||||||
|
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getCashOutListFn">
|
||||||
|
<view v-for="(item,index) in cashOutList" :key="item.id" class="member-record-item" @click="toDetailFn(item)">
|
||||||
|
<view class="name">{{item.transfer_type_name}}</view>
|
||||||
|
<view class="desc">{{t('applyTime')}}: {{item.create_time}}</view>
|
||||||
|
<view class="desc">{{ item.status != -1 ? currentStatusDesc(item.status) : item.refuse_reason}}</view>
|
||||||
|
<view class="money" :class="item.apply_money > 0 ? 'text-active' : ''">
|
||||||
|
{{ item.apply_money > 0 ? '+' + item.apply_money : item.apply_money }}
|
||||||
|
</view>
|
||||||
|
<view class="state">{{ item.status_name }}</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-empty v-if="!cashOutList.length && loading" :option="{tip : t('emptyTip')}"></mescroll-empty>
|
||||||
|
</mescroll-body>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { redirect, img } from '@/utils/common';
|
||||||
|
import { getCashOutList } from '@/app/api/member';
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
|
||||||
|
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
|
||||||
|
|
||||||
|
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
|
||||||
|
|
||||||
|
const cashOutList = ref<Array<any>>([]);
|
||||||
|
const mescrollRef = ref(null);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
let account_type = uni.getStorageSync('cashOutAccountType')
|
||||||
|
const currentStatusDesc = (status) =>{
|
||||||
|
switch(status){
|
||||||
|
case 1:
|
||||||
|
return t('toBeReviewed')
|
||||||
|
case 2:
|
||||||
|
return t('toBeTransfer')
|
||||||
|
case 3:
|
||||||
|
return t('transfer')
|
||||||
|
case -2:
|
||||||
|
return t('cancelApply')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCashOutListFn = (mescroll)=>{
|
||||||
|
let data:any = {}
|
||||||
|
loading.value = false;
|
||||||
|
data.page = mescroll.num;
|
||||||
|
data.page_size = mescroll.size;
|
||||||
|
data.account_type = account_type;
|
||||||
|
getCashOutList(data).then((res) => {
|
||||||
|
let newArr = res.data.data;
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1){
|
||||||
|
cashOutList.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
cashOutList.value = cashOutList.value.concat(newArr);
|
||||||
|
loading.value = true;
|
||||||
|
}).catch(()=>{
|
||||||
|
loading.value = true;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const toDetailFn = (data)=>{
|
||||||
|
redirect({ url: '/app/pages/member/cash_out_detail', param: { id: data.id }});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '@/styles/member_record_list.scss';
|
||||||
|
</style>
|
||||||
80
uni-app/src/app/pages/member/cash_out_detail.vue
Normal file
80
uni-app/src/app/pages/member/cash_out_detail.vue
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<view class="member-record-detail" :style="themeColor()">
|
||||||
|
<block v-if="!loading">
|
||||||
|
<view class="money-wrap">
|
||||||
|
<text>-{{ cashOutInfo.apply_money }}</text>
|
||||||
|
<text>{{ cashOutInfo.status_name }}</text>
|
||||||
|
</view>
|
||||||
|
<!-- 状态0待审核1.待转账2已转账 -1拒绝' -->
|
||||||
|
<view class="item">
|
||||||
|
<view class="line-wrap">
|
||||||
|
<text class="label w-[200rpx]">{{t('cashOutNo')}}</text>
|
||||||
|
<text class="value">{{ cashOutInfo.cash_out_no }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap">
|
||||||
|
<text class="label w-[200rpx]">{{t('serviceMoney')}}</text>
|
||||||
|
<text class="value">¥{{ cashOutInfo.service_money }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap">
|
||||||
|
<text class="label w-[200rpx]">{{t('createTime')}}</text>
|
||||||
|
<text class="value">{{ cashOutInfo.create_time }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap" v-if="cashOutInfo.status && cashOutInfo.audit_time">
|
||||||
|
<text class="label w-[200rpx]">{{t('auditTime')}}</text>
|
||||||
|
<text class="value">{{ cashOutInfo.audit_time }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap" v-if="cashOutInfo.transfer_bank">
|
||||||
|
<text class="label w-[200rpx]">{{t('transferBank')}}</text>
|
||||||
|
<text class="value truncate">{{ cashOutInfo.transfer_bank }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap">
|
||||||
|
<text class="label w-[200rpx]">{{t('transferAccount')}}</text>
|
||||||
|
<text class="value truncate">{{ cashOutInfo.transfer_type == 'wechatpay' ? '微信' : cashOutInfo.transfer_account }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap" v-if="cashOutInfo.status == -1 && cashOutInfo.refuse_reason">
|
||||||
|
<text class="label w-[200rpx]">{{t('refuseReason')}}</text>
|
||||||
|
<text class="value truncate">{{ cashOutInfo.refuse_reason }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap" v-if="cashOutInfo.status == 2">
|
||||||
|
<text class="label w-[200rpx]">{{t('transferTypeName')}}</text>
|
||||||
|
<text class="value truncate">{{ cashOutInfo.transfer_type_name }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="line-wrap" v-if="cashOutInfo.status == 2 && cashOutInfo.transfer_time">
|
||||||
|
<text class="label w-[200rpx]">{{t('transferTime')}}</text>
|
||||||
|
<text class="value truncate">{{ cashOutInfo.transfer_time }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { redirect, img } from '@/utils/common';
|
||||||
|
import { getCashOutDetail } from '@/app/api/member';
|
||||||
|
|
||||||
|
const cashOutInfo = ref({});
|
||||||
|
const loading = ref<boolean>(true);
|
||||||
|
onLoad((option: any) => {
|
||||||
|
let id = option.id || "";
|
||||||
|
getCashoutAccountListFn(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getCashoutAccountListFn = (id) => {
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
getCashOutDetail(id).then((res) => {
|
||||||
|
cashOutInfo.value = res.data;
|
||||||
|
loading.value = false;
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '@/styles/member_record_detail.scss';
|
||||||
|
</style>
|
||||||
192
uni-app/src/app/pages/member/commission.vue
Normal file
192
uni-app/src/app/pages/member/commission.vue
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<template>
|
||||||
|
<view class="bg-[#F6F6F6] min-h-[100vh] w-full" :style="themeColor()" v-if="memberStore.info">
|
||||||
|
<view class="fixed w-full z-2 !bg-[#F6F6F6]">
|
||||||
|
<view class="pb-[272rpx]" :style="headerStyle">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<top-tabbar :data="param" class="top-header"/>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
<view class="mt-[-232rpx] sidebar-marign" :style="{ backgroundImage: 'url(' + img('static/resource/images/member/commission/account_bg.png') + ')',backgroundRepeat:'no-repeat',backgroundSize:'100% 100%'}">
|
||||||
|
<view class="pt-[40rpx]">
|
||||||
|
<view class="flex items-center justify-between px-[30rpx]">
|
||||||
|
<view>
|
||||||
|
<view class="text-[26rpx] font-400 text-[#fff] leading-[36rpx] mb-[16rpx]">{{t('accountCommission')}}</view>
|
||||||
|
<view class="font-bold text-[#fff] flex items-baseline">
|
||||||
|
<text class="text-[56rpx] h-[72rpx] price-font">{{ memberStore.info ? (moneyFormat(memberStore.info.commission).split(".")[0]+'.') : '0.' }}</text>
|
||||||
|
<text class="text-[44rpx] h-[56rpx] price-font">{{ memberStore.info ? moneyFormat(memberStore.info.commission).split(".")[1] : '00' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button @click="applyCashOut" hover-class="none" class="bg-[#fff] rounded-[100rpx] w-[150rpx] h-[66rpx] leading-[66rpx] text-[#EF000C] m-[0] border-[0] text-[32rpx]">{{t('transferMoney')}}</button>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center mt-[68rpx] px-[30rpx] border-[0] border-t-[2rpx] border-solid border-[rgba(255,255,255,.3)] h-[126rpx]">
|
||||||
|
<view class="flex-1">
|
||||||
|
<view class="font-bold text-[#fff] text-[36rpx] leading-[44rpx] mb-[6rpx] price-font">
|
||||||
|
{{ moneyFormat(memberStore.info?.commission_get)|| '0.00' }}
|
||||||
|
</view>
|
||||||
|
<view class="text-[26rpx] text-[#fff] leading-[36rpx]">{{ t('commission') }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex-1">
|
||||||
|
<view class="font-bold text-[#fff] text-[36rpx] leading-[44rpx] mb-[6rpx] price-font">
|
||||||
|
{{ moneyFormat(memberStore.info?.commission_cash_outing)|| '0.00' }}
|
||||||
|
</view>
|
||||||
|
<view class="text-[26rpx] text-[#fff] leading-[36rpx]">{{ t('money') }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[40rpx] tab-style-1">
|
||||||
|
<view class="tab-left">
|
||||||
|
<view class="tab-left-item" :class="{ 'class-select': fromType.from_type === item.from_type && fromType.account_data_gt === item.account_data_gt }" @click="fromTypeFn(item,index)" v-for="(item, index) in accountTypeList">{{ item.name }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="tab-right" @click="handleSelect">
|
||||||
|
<view class="tab-right-date">日期</view>
|
||||||
|
<view class="nc-iconfont nc-icon-riliV6xx tab-right-icon"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="geCommissionListFn" :top="mescrollTop">
|
||||||
|
<view class="px-[var(--sidebar-m)] pt-[20rpx] body-bottom" v-if="list.length">
|
||||||
|
<view v-for="(item,index) in list" :key="item.id" class="w-full h-[140rpx] flex justify-between items-center card-template" :class="{'mt-[20rpx]':index}">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="w-[80rpx] h-[80rpx] text-center rounded-[40rpx] text-[40rpx] font-500 leading-[80rpx] text-[#fff]"
|
||||||
|
:class="{'bg-[#EF000C]' :item.account_data > 0, 'bg-[#1379FF]':item.account_data <= 0 }">
|
||||||
|
{{item.account_data > 0?'收':'提'}}
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-col ml-[20rpx]">
|
||||||
|
<view class="text-[#333] text-[26rpx] leading-[36rpx]">{{item.from_type_name}}</view>
|
||||||
|
<view class="text-[#8288A2] text-[24rpx] leading-[34rpx] mt-[4rpx] font-400">{{item.create_time}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-[36rpx] leading-[50rpx]" :class="{'text-[#EF000C]' :item.account_data > 0, 'text-[#333]':item.account_data <= 0 }">{{ item.account_data > 0 ? '+' + item.account_data : item.account_data }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="box-border pt-[20rpx] px-[30rpx] body-bottom" :style="{'height':'calc(100vh - '+ mescrollTop +')'}" v-if="!list.length && !loading &&!listLoading">
|
||||||
|
<view class="h-full rounded-[16rpx] flex items-center justify-center">
|
||||||
|
<mescroll-empty></mescroll-empty>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</mescroll-body>
|
||||||
|
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
|
||||||
|
<!-- 时间选择 -->
|
||||||
|
<select-date ref="selectDateRef" @confirm="confirmFn" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, reactive } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { moneyFormat, redirect, img } from '@/utils/common';
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import { getMemberCommission } from '@/app/api/member';
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
|
||||||
|
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
|
||||||
|
import { topTabar } from '@/utils/topTabbar'
|
||||||
|
import selectDate from '@/components/select-date/select-date.vue';
|
||||||
|
|
||||||
|
const { downCallback,mescrollInit, getMescroll } = useMescroll(onPageScroll, onReachBottom);
|
||||||
|
const memberStore = useMemberStore();
|
||||||
|
const info = computed(() => memberStore.info)
|
||||||
|
// 提现
|
||||||
|
const applyCashOut = ()=> {
|
||||||
|
uni.setStorageSync('cashOutAccountType', 'commission')
|
||||||
|
redirect({ url: '/app/pages/member/apply_cash_out' })
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* 自定义头部 - start ***********/
|
||||||
|
const topTabarObj = topTabar()
|
||||||
|
let param = topTabarObj.setTopTabbarParam({title:'我的佣金',topStatusBar:{bgColor: '#fff',textColor: '#333'}})
|
||||||
|
/********* 自定义头部 - end ***********/
|
||||||
|
|
||||||
|
// 获取系统状态栏的高度
|
||||||
|
let menuButtonInfo:any = {};
|
||||||
|
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
|
||||||
|
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||||
|
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
|
||||||
|
// #endif
|
||||||
|
const headerStyle = computed(()=>{
|
||||||
|
return {
|
||||||
|
backgroundImage: 'url(' + img('static/resource/images/member/commission/commission_bg.png') + ') ',
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'bottom',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 16为自定头部的padding-bottom
|
||||||
|
const mescrollTop = computed(()=>{
|
||||||
|
return Object.keys(menuButtonInfo).length? (Number(menuButtonInfo.height) * 2 + menuButtonInfo.top * 2 + 486 + 16)+'rpx':'504rpx'
|
||||||
|
})
|
||||||
|
|
||||||
|
//来源类型
|
||||||
|
const fromType = ref({
|
||||||
|
from_type:'',
|
||||||
|
account_data_gt:''
|
||||||
|
})
|
||||||
|
const accountTypeList = ref([
|
||||||
|
{name:'全部',from_type:'',account_data_gt: ''},
|
||||||
|
{name:'佣金',from_type:'',account_data_gt: 0},
|
||||||
|
{name:'提现',from_type:'cash_out',account_data_gt: ''},
|
||||||
|
])
|
||||||
|
const create_time = ref([])
|
||||||
|
const list = ref<Array<any>>([])
|
||||||
|
const loading = ref<boolean>(true)
|
||||||
|
const listLoading = ref<boolean>(true)
|
||||||
|
const mescrollRef = ref(null);
|
||||||
|
|
||||||
|
const fromTypeFn = (data : any ,index : number)=>{
|
||||||
|
fromType.value.from_type = data.from_type
|
||||||
|
fromType.value.account_data_gt = data.account_data_gt
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
const geCommissionListFn = (mescroll) => {
|
||||||
|
listLoading.value = true;
|
||||||
|
let data : Object = {
|
||||||
|
page: mescroll.num,
|
||||||
|
limit: mescroll.size,
|
||||||
|
from_type:fromType.value.from_type,
|
||||||
|
account_data_gt: fromType.value.account_data_gt,
|
||||||
|
create_time:create_time.value
|
||||||
|
}
|
||||||
|
getMemberCommission(data).then((res:any) => {
|
||||||
|
let newArr = res.data.data;-
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1) {
|
||||||
|
list.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
list.value = list.value.concat(newArr);
|
||||||
|
listLoading.value = false;
|
||||||
|
loading.value = false;
|
||||||
|
}).catch(() => {
|
||||||
|
listLoading.value = false;
|
||||||
|
loading.value = false;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//日期筛选
|
||||||
|
const selectDateRef = ref()
|
||||||
|
const handleSelect = () =>{
|
||||||
|
selectDateRef.value.show = true
|
||||||
|
}
|
||||||
|
// 确定时间筛选
|
||||||
|
const confirmFn = (data) =>{
|
||||||
|
create_time.value = data;
|
||||||
|
list.value = []
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.member-level{
|
||||||
|
background: linear-gradient( 360deg, #F23621 11%, #FF7F71 100%), #D9D9D9;
|
||||||
|
border-radius: 0rpx 20rpx 20rpx 0rpx;
|
||||||
|
}
|
||||||
|
:deep(.uni-scroll-view){
|
||||||
|
overflow: auto hidden !important;
|
||||||
|
}
|
||||||
|
.body-bottom{
|
||||||
|
padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
|
||||||
|
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
192
uni-app/src/app/pages/member/components/select-date.vue
Normal file
192
uni-app/src/app/pages/member/components/select-date.vue
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<template>
|
||||||
|
<u-popup :show="show" @close="show = false" mode="bottom" :round="10" >
|
||||||
|
<view>
|
||||||
|
<view class="py-[30rpx] px-[40rpx] flex items-center justify-between">
|
||||||
|
<view class="text-center flex-1">选择时间</view>
|
||||||
|
<view class="nc-iconfont nc-icon-guanbiV6xx text-[36rpx] text-primary" @click="show = false"></view>
|
||||||
|
</view>
|
||||||
|
<view class="px-[30rpx] mb-[20rpx]">
|
||||||
|
<view class="flex items-center justify-between mb-[30rpx]">
|
||||||
|
<view class="w-[160rpx] h-[60rpx] leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" v-for="(item,index) in curselectDate" :key="'a'+index" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == item.type}" @click="loadDateFn(item)">{{item.name}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center justify-between">
|
||||||
|
<view class="w-[316rpx] h-[60rpx] leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == 'first'}" @click="currentValue.type = 'first'">{{dateList.nowDate[0]}}</view>
|
||||||
|
<view class="nc-iconfont nc-icon-jianV6xx"></view>
|
||||||
|
<view class="w-[316rpx] h-[60rpx] leading-[60rpx] rounded-[30rpx] bg-[#F4F6FA] text-center text-[26rpx] text-[#666] border-[2rpx] border-solid border-[#F4F6FA]" :class="{'text-primary !border-[var(--primary-color)] !bg-[rgba(239,0,12,0.04)]': currentValue.type == 'second'}" @click="currentValue.type = 'second'">{{dateList.nowDate[1]}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="h-[396rpx]">
|
||||||
|
<picker-view :indicator-style="{height:'70rpx',backgroundColor:'#F4F6FA'}" :value="dateList.curIndex" @change="bindChange" class="px-[60rpx] h-full">
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="text-center leading-[70rpx] !h-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.years" :key="index">{{item}}年</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="text-center leading-[70rpx] !h-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.months" :key="index">{{item}}月</view>
|
||||||
|
</picker-view-column>
|
||||||
|
<picker-view-column>
|
||||||
|
<view class="text-center leading-[70rpx] !h-[70rpx] text-[28rpx]" v-for="(item,index) in dateList.days" :key="index">{{item}}日</view>
|
||||||
|
</picker-view-column>
|
||||||
|
</picker-view>
|
||||||
|
</view>
|
||||||
|
<view class="px-[30rpx] pb-[30rpx] pt-[20rpx] flex justify-between">
|
||||||
|
<button class="w-[330rpx] h-[88rpx] text-[var(--primary-color)] text-[32rpx] leading-[84rpx] border-[2rpx] border-solid border-[var(--primary-color)] rounded-[100rpx] bg-transparent" @click="reset">重置</button>
|
||||||
|
<button class="w-[330rpx] h-[88rpx] text-[#fff] text-[32rpx] leading-[88rpx] border-[0] rounded-[100rpx] primary-btn-bg" shape="circle" @click="save">确定</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref,reactive } from 'vue'
|
||||||
|
|
||||||
|
const emits = defineEmits(['confirm'])
|
||||||
|
// 弹框时间选择
|
||||||
|
const show = ref(false)
|
||||||
|
const create_time = ref([])
|
||||||
|
// 日期
|
||||||
|
const init = () =>{
|
||||||
|
const date = new Date();
|
||||||
|
const years = []
|
||||||
|
const months = []
|
||||||
|
const days = []
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth();
|
||||||
|
const day = date.getDate()
|
||||||
|
|
||||||
|
for (let i = 1990; i <= date.getFullYear()+2; i++) {
|
||||||
|
years.push(i)
|
||||||
|
}
|
||||||
|
for (let i = 1; i <= 12; i++) {
|
||||||
|
months.push(i)
|
||||||
|
}
|
||||||
|
let dayCount = getDaysInMonth(year, month+1)
|
||||||
|
for (let i = 1; i <= dayCount; i++) {
|
||||||
|
days.push(i)
|
||||||
|
}
|
||||||
|
let yearIndex = years.indexOf(year)
|
||||||
|
let curIndex = [yearIndex, month, day-1]
|
||||||
|
let nowDate = `${year}-${month + 1 < 10 ? '0' + (month + 1) :(month + 1) }-${day < 10 ? '0' + day :day }`
|
||||||
|
let lastMonthDate = new Date(date.getFullYear(),month - 1,date.getDate())
|
||||||
|
let lastThreeMonthDate = new Date(date.getFullYear(),month - 3,date.getDate())
|
||||||
|
let halfYear = new Date(date.getFullYear(), month - 6, date.getDate())
|
||||||
|
let lastYear =new Date(date.getFullYear() - 1, month, date.getDate())
|
||||||
|
const formatDate = (dateTime:any) => {
|
||||||
|
const yearTime = dateTime.getFullYear()
|
||||||
|
const monthTime = dateTime.getMonth() + 1
|
||||||
|
const dayTime = dateTime.getDate()
|
||||||
|
return `${yearTime}-${monthTime < 10 ? '0' + monthTime : monthTime}-${dayTime < 10 ? '0' + dayTime :dayTime }`
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
years,
|
||||||
|
months,
|
||||||
|
days,
|
||||||
|
curIndex,
|
||||||
|
nowDate,
|
||||||
|
lastMonth: formatDate(lastMonthDate),
|
||||||
|
lastThreeMonth: formatDate(lastThreeMonthDate),
|
||||||
|
halfYear: formatDate(halfYear),
|
||||||
|
lastYear: formatDate(lastYear)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getDaysInMonth = (year, month) => {
|
||||||
|
let date = new Date(year, month, 0).getDate()
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
const getDaysCount = (year, month) =>{
|
||||||
|
let count = getDaysInMonth(year, month)
|
||||||
|
let days = []
|
||||||
|
for (let i = 1; i <= count; i++) {
|
||||||
|
days.push(i)
|
||||||
|
}
|
||||||
|
return days
|
||||||
|
}
|
||||||
|
const dateList = reactive({
|
||||||
|
years: init().years,
|
||||||
|
months: init().months,
|
||||||
|
days: init().days,
|
||||||
|
curIndex:init().curIndex, //当前选中下标
|
||||||
|
nowDate:[init().nowDate,init().nowDate] //当前选中日期
|
||||||
|
})
|
||||||
|
|
||||||
|
const bindChange = (e) =>{
|
||||||
|
const val = e.detail.value
|
||||||
|
let year = dateList.years[val[0]]
|
||||||
|
let month= dateList.months[val[1]]
|
||||||
|
let day = dateList.days[val[2]]
|
||||||
|
// 根据年份,月份判断天数
|
||||||
|
dateList.days = getDaysCount(year, month)
|
||||||
|
if(currentValue.value.type == 'first'){
|
||||||
|
dateList.nowDate[0] = `${year}-${month < 10 ? '0' + month :month }-${day < 10 ? '0' + day :day }`
|
||||||
|
}else if(currentValue.value.type == 'second'){
|
||||||
|
dateList.nowDate[1] = `${year}-${month < 10 ? '0' + month :month }-${day < 10 ? '0' + day :day }`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const curselectDate = reactive([
|
||||||
|
{
|
||||||
|
time:[init().lastMonth,init().nowDate],
|
||||||
|
type:'lastMonth',
|
||||||
|
name:'近1个月'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
time:[init().lastThreeMonth,init().nowDate],
|
||||||
|
type:'lastThreeMonth',
|
||||||
|
name:'近3个月'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
time:[init().halfYear,init().nowDate],
|
||||||
|
type:'halfYear',
|
||||||
|
name:'近半年'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
time:[init().lastYear,init().nowDate],
|
||||||
|
type:'lastYear',
|
||||||
|
name:'近一年'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
// 时间搜索
|
||||||
|
const currentValue = ref({
|
||||||
|
type: 'first',
|
||||||
|
time: []
|
||||||
|
})
|
||||||
|
const loadDateFn = (data) =>{
|
||||||
|
currentValue.value.type = data.type
|
||||||
|
currentValue.value.time = data.time
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = () =>{
|
||||||
|
if(currentValue.value.type == 'first' ||currentValue.value.type == 'second'){
|
||||||
|
create_time.value = dateList.nowDate
|
||||||
|
let start = new Date(create_time.value[0]).getTime()
|
||||||
|
let end = new Date(create_time.value[1]).getTime()
|
||||||
|
if( start > end){
|
||||||
|
uni.showToast({ title: '开始时间不能大于结束时间', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
create_time.value = currentValue.value.time
|
||||||
|
}
|
||||||
|
emits('confirm',create_time.value)
|
||||||
|
show.value = false
|
||||||
|
}
|
||||||
|
const reset = () =>{
|
||||||
|
currentValue.value.type = 'first'
|
||||||
|
dateList.curIndex = init().curIndex
|
||||||
|
dateList.nowDate = [init().nowDate,init().nowDate]
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
:deep(.uni-picker-view-content){
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
:deep(.uni-picker-view-indicator::before){
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
:deep(.uni-picker-view-indicator::after){
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
49
uni-app/src/app/pages/member/contact.vue
Normal file
49
uni-app/src/app/pages/member/contact.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<view class="flex items-center justify-center min-h-[100vh]" :style="themeColor()">
|
||||||
|
<view class="contact-wrap pt-[5%]">
|
||||||
|
<image :src="img('static/resource/images/member/contact_service.png')" mode="widthFix" />
|
||||||
|
<view class="mt-[40rpx] text-[28rpx]">
|
||||||
|
欢迎您联系我们,提供您宝贵的意见!
|
||||||
|
</view>
|
||||||
|
<nc-contact
|
||||||
|
:send-message-title="sendMessageTitle"
|
||||||
|
:send-message-path="sendMessagePath"
|
||||||
|
:send-message-img="sendMessageImg">
|
||||||
|
<button type="primary" class="btn-wrap primary-btn-bg">{{ t('customerService') }}</button>
|
||||||
|
</nc-contact>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { img } from '@/utils/common';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const sendMessageTitle = ref('')
|
||||||
|
const sendMessagePath = ref('')
|
||||||
|
const sendMessageImg = ref('')
|
||||||
|
|
||||||
|
sendMessageImg.value = img('static/resource/images/member/contact_service.png')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.contact-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
image {
|
||||||
|
width: 674rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-wrap {
|
||||||
|
margin-top: 120rpx;
|
||||||
|
width: 530rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
border-radius: 50rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
162
uni-app/src/app/pages/member/detailed_account.vue
Normal file
162
uni-app/src/app/pages/member/detailed_account.vue
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<view class="min-h-[100vh] bg-[#F6F6F6] overflow-hidden" :style="themeColor()">
|
||||||
|
<view class="fixed left-0 right-0 top-0 z-99">
|
||||||
|
<view class="bg-[#fff] px-[var(--sidebar-m)] h-[88rpx] flex items-center">
|
||||||
|
<view class="flex-1 flex items-center h-[60rpx] bg-[#F8F9FD] rounded-[30rpx] px-[20rpx]">
|
||||||
|
<u-input class="flex-1" maxlength="50" v-model="keyword" @confirm="searchTypeFn()" placeholder="请输入搜索关键词" placeholderClass="text-[#999] text-[24rpx]" fontSize="26rpx" clearable border="none"></u-input>
|
||||||
|
<text class="nc-iconfont nc-icon-sousuo-duanV6xx1 text-[28rpx] ml-[32rpx] !text-[#999]" @click="searchTypeFn()"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="tab-style-1 pt-[14rpx] bg-[#fff]">
|
||||||
|
<view class="tab-left">
|
||||||
|
<view class="tab-left-item" :class="{'!text-primary class-select':fromType.from_type === item.from_type && fromType.account_data_gt === item.account_data_gt}" v-for="(item,index) in accountTypeList" :key="index" @click="fromTypeFn(item,index)">{{ item.name }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="tab-right" @click="handleSelect">
|
||||||
|
<view class="tab-right-date">日期</view>
|
||||||
|
<view class="nc-iconfont nc-icon-riliV6xx tab-right-icon"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getListFn" top="196rpx">
|
||||||
|
<view v-for="(item,index) in list" :key="item.id" class="sidebar-marign mb-[20rpx] card-template relative">
|
||||||
|
<view class="flex items-center justify-between mb-[10rpx]">
|
||||||
|
<view class="text-[28rpx] font-500 text-[#333] leading-[40rpx]">{{item.from_type_name}}</view>
|
||||||
|
<view class="absolute right-[30rpx] top-[30rpx] text-[36rpx] font-500 text-[#03B521] leading-[50rpx]" :class="{'!text-[var(--price-text-color)]':item.account_data > 0}">{{ item.account_data > 0 ? '+' + item.account_data : item.account_data }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-[24rpx] leading-[34rpx] text-[#8288A2] mb-[10rpx]" v-if="item.memo">{{item.memo}}</view>
|
||||||
|
<view class="text-[24rpx] leading-[34rpx] text-[#8288A2]">{{item.create_time}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="mx-[30rpx] rounded-[16rpx] noData flex items-center justify-center" v-if="!list.length && loading">
|
||||||
|
<mescroll-empty :option="{tip : tip}"></mescroll-empty>
|
||||||
|
</view>
|
||||||
|
</mescroll-body>
|
||||||
|
<!-- 时间选择 -->
|
||||||
|
<select-date ref="selectDateRef" @confirm="confirmFn" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref,nextTick, reactive } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
|
||||||
|
import { getBalanceList, getMoneyList, getCommissionList} from '@/app/api/member';
|
||||||
|
import { onPageScroll, onReachBottom, onLoad, onShow } from '@dcloudio/uni-app';
|
||||||
|
import selectDate from '@/components/select-date/select-date.vue';
|
||||||
|
|
||||||
|
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
|
||||||
|
|
||||||
|
const type = ref('')
|
||||||
|
const tip = ref('')
|
||||||
|
|
||||||
|
onLoad((options: any) => {
|
||||||
|
type.value = options.type || 'balance';
|
||||||
|
nextTick(()=>{
|
||||||
|
setTimeout(()=>{
|
||||||
|
if(type.value == 'balance'){
|
||||||
|
tip.value = t('balanceEmptyTip')
|
||||||
|
}else if(type.value == 'money'){
|
||||||
|
tip.value = t('moneyEmptyTip')
|
||||||
|
}else if(type.value == 'commission'){
|
||||||
|
tip.value = t('commissionEmptyTip')
|
||||||
|
}
|
||||||
|
},100);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const keyword = ref<string>('')
|
||||||
|
const create_time = ref([])
|
||||||
|
//来源类型
|
||||||
|
const fromType = ref({
|
||||||
|
from_type:'',
|
||||||
|
account_data_gt:''
|
||||||
|
})
|
||||||
|
const accountTypeList = ref([
|
||||||
|
{name:'全部',from_type:'',account_data_gt: ''},
|
||||||
|
{name:'佣金',from_type:'',account_data_gt: 0},
|
||||||
|
{name:'提现',from_type:'cash_out',account_data_gt: ''},
|
||||||
|
])
|
||||||
|
const list = ref<Array<any>>([]),
|
||||||
|
loading = ref<boolean>(false),
|
||||||
|
mescrollRef = ref(null);
|
||||||
|
|
||||||
|
interface mescrollStructure {
|
||||||
|
num : number,
|
||||||
|
size : number,
|
||||||
|
endSuccess : Function,
|
||||||
|
[propName : string] : any
|
||||||
|
}
|
||||||
|
|
||||||
|
const getListFn = (mescroll : mescrollStructure) => {
|
||||||
|
loading.value = false;
|
||||||
|
let data : Object = {
|
||||||
|
page: mescroll.num,
|
||||||
|
page_size: mescroll.size,
|
||||||
|
keyword:keyword.value,
|
||||||
|
create_time:create_time.value,
|
||||||
|
from_type:fromType.value.from_type,
|
||||||
|
account_data_gt: fromType.value.account_data_gt
|
||||||
|
};
|
||||||
|
interface acceptingDataStructure {
|
||||||
|
data : acceptingDataItemStructure,
|
||||||
|
msg : string,
|
||||||
|
code : number
|
||||||
|
}
|
||||||
|
interface acceptingDataItemStructure {
|
||||||
|
data : object,
|
||||||
|
[propName : string] : number | string | object
|
||||||
|
}
|
||||||
|
|
||||||
|
let fnList = (params : any) => { };
|
||||||
|
if (type.value == 'balance') fnList = getBalanceList;
|
||||||
|
else if (type.value == 'money') fnList = getMoneyList;
|
||||||
|
else if (type.value == 'commission') fnList = getCommissionList;
|
||||||
|
|
||||||
|
fnList(data).then((res : acceptingDataStructure) => {
|
||||||
|
let newArr = res.data.data;
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1) {
|
||||||
|
list.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
list.value = list.value.concat(newArr);
|
||||||
|
loading.value = true;
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = true;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关键词搜索条件搜索
|
||||||
|
const searchTypeFn = () =>{
|
||||||
|
list.value = [];
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
// 类型搜索
|
||||||
|
const fromTypeFn = (data : any ,index : number)=>{
|
||||||
|
fromType.value.from_type = data.from_type
|
||||||
|
fromType.value.account_data_gt = data.account_data_gt
|
||||||
|
list.value = []
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
//日期筛选
|
||||||
|
const selectDateRef = ref()
|
||||||
|
const handleSelect = () =>{
|
||||||
|
selectDateRef.value.show = true
|
||||||
|
}
|
||||||
|
// 确定时间筛选
|
||||||
|
const confirmFn = (data) =>{
|
||||||
|
create_time.value = data;
|
||||||
|
list.value = []
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.noData{
|
||||||
|
height: calc(100vh - 210rpx - constant(safe-area-inset-bottom));
|
||||||
|
height: calc(100vh - 210rpx - env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
93
uni-app/src/app/pages/member/index.vue
Normal file
93
uni-app/src/app/pages/member/index.vue
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
|
||||||
|
<u-loading-page :loading="diy.getLoading()" loadingText="" bg-color="#f7f7f7" />
|
||||||
|
|
||||||
|
<view v-show="!diy.getLoading()">
|
||||||
|
|
||||||
|
<!-- 自定义模板渲染 -->
|
||||||
|
<view class="diy-template-wrap bg-index" v-if="diy.data.pageMode != 'fixed'" :style="diy.pageStyle()">
|
||||||
|
|
||||||
|
<diy-group ref="diyGroupRef" :data="diy.data" :pullDownRefreshCount="diy.pullDownRefreshCount" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 固定模板渲染 -->
|
||||||
|
<view class="fixed-template-wrap" v-if="diy.data.pageMode == 'fixed'">
|
||||||
|
|
||||||
|
<fixed-group :data="diy.data" :pullDownRefreshCount="diy.pullDownRefreshCount" />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref, computed} from 'vue';
|
||||||
|
import {useDiy} from '@/hooks/useDiy'
|
||||||
|
import {redirect} from '@/utils/common';
|
||||||
|
import diyGroup from '@/addon/components/diy/group/index.vue'
|
||||||
|
import fixedGroup from '@/addon/components/fixed/group/index.vue'
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
|
||||||
|
// 会员信息
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
const userInfo = computed(() => memberStore.info)
|
||||||
|
|
||||||
|
const diy = useDiy({
|
||||||
|
name: 'DIY_MEMBER_INDEX'
|
||||||
|
})
|
||||||
|
|
||||||
|
const diyGroupRef = ref(null)
|
||||||
|
|
||||||
|
// 监听页面加载
|
||||||
|
diy.onLoad();
|
||||||
|
|
||||||
|
// 监听页面显示
|
||||||
|
diy.onShow((data: any) => {
|
||||||
|
if (data.value) {
|
||||||
|
// uni.setNavigationBarTitle({
|
||||||
|
// title: diyData.title
|
||||||
|
// })
|
||||||
|
} else if (data.page) {
|
||||||
|
// 跳转到设置的启动页
|
||||||
|
redirect({url: data.page, mode: 'reLaunch'})
|
||||||
|
}
|
||||||
|
diyGroupRef.value?.refresh();
|
||||||
|
if (userInfo.value) {
|
||||||
|
useMemberStore().getMemberInfo()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听页面卸载
|
||||||
|
diy.onUnload();
|
||||||
|
|
||||||
|
// 监听下拉刷新事件
|
||||||
|
diy.onPullDownRefresh()
|
||||||
|
|
||||||
|
// 监听滚动事件
|
||||||
|
diy.onPageScroll()
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '@/styles/diy.scss';
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.diy-template-wrap {
|
||||||
|
/* #ifdef MP */
|
||||||
|
.child-diy-template-wrap {
|
||||||
|
::v-deep .diy-group {
|
||||||
|
> .draggable-element.top-fixed-diy {
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
321
uni-app/src/app/pages/member/level.vue
Normal file
321
uni-app/src/app/pages/member/level.vue
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<u-loading-page :loading="loading && memberInfo" loadingText="" bg-color="#f7f7f7"></u-loading-page>
|
||||||
|
<view v-if="!loading && memberInfo && list && list.length" class=" min-h-[100vh] overflow-hidden flex flex-col" :style="{backgroundColor: currLevelInfo.level_style.bg_color }">
|
||||||
|
<!-- #ifdef MP -->
|
||||||
|
<top-tabbar :data="topTabbarData" :scrollBool="topTabarObj.getScrollBool()"/>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view>
|
||||||
|
<view class="pt-[40rpx] mb-[20rpx]">
|
||||||
|
<!-- 轮播图 -->
|
||||||
|
<view class="relative">
|
||||||
|
<swiper class="swiper ns-indicator-dots relative" :style="{ height: '300rpx' }" @change="swiperChange" :current = "swiperIndex" previous-margin="48rpx" next-margin="48rpx">
|
||||||
|
<swiper-item class="swiper-item" v-for="(item,index) in list" :key="item.id">
|
||||||
|
<view class="h-[300rpx] relative">
|
||||||
|
<view v-if="memberInfo.member_level == item.level_id && swiperIndex == index" class="text-[24rpx] absolute top-0 left-0 z-10 h-[66rpx] !bg-contain w-[150rpx] flex pt-[12rpx] pl-[16rpx] box-border" :style="{ background: 'url(' + img(currLevelInfo.level_tag) + ') no-repeat',color: currLevelInfo.level_style.level_color}">
|
||||||
|
当前等级
|
||||||
|
</view>
|
||||||
|
<view class="absolute top-0 left-0 right-0 bottom-0 z-20 px-[30rpx] pt-[76rpx] box-border" :class="{'px-[50rpx]': swiperIndex != index}">
|
||||||
|
<view class="flex items-center leading-[50rpx] mb-[70rpx]">
|
||||||
|
<image class="h-[32rpx] w-[34rpx] align-middle" :src="img(item.level_icon ? item.level_icon : '')" mode="aspectFill" />
|
||||||
|
<view class="text-[36rpx] font-bold ml-[10rpx] max-w-[340rpx] truncate" :style="{color:currLevelInfo.level_style.level_color}">{{item.level_name}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center" :style="{color: currLevelInfo.level_style.level_color}">
|
||||||
|
<view class="text-[28rpx] font-bold leading-[38rpx]">{{ memberInfo.growth }}</view>
|
||||||
|
<view class="text-[24rpx] leading-[34rpx] font-500">/{{list[index].growth}}成长值</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-between items-center mt-[10rpx]">
|
||||||
|
<view class="flex flex-col flex-1">
|
||||||
|
<view>
|
||||||
|
<progress :percent="progress(index)" :border-radius="100" :activeColor="currLevelInfo.level_style.level_color" backgroundColor="#fff" stroke-width="6" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="relatvie h-full w-full">
|
||||||
|
<image class="h-full w-full" :src="img(item.level_bg)" mode="aspectFit" :class="{'swiper-animation': swiperIndex != index}" :show-menu-by-longpress="true"/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mb-[30rpx] relative">
|
||||||
|
<view class="bg-[#fff] opacity-15 h-[2rpx] w-full absolute top-[15rpx]"></view>
|
||||||
|
<view :style="lineStyle" class="bg-[#fff] opacity-60 h-[2rpx] absolute top-[15rpx] z-4 left-[50%]"></view>
|
||||||
|
<view class="mx-[86rpx]">
|
||||||
|
<scroll-view :scroll-x="true" scroll-with-animation :scroll-into-view="'id' + ( levelIndex ? levelIndex - 1 : 0)">
|
||||||
|
<view class="flex flex-nowrap py-[10rpx]">
|
||||||
|
<block v-for="(item,index) in list" :key="item.id">
|
||||||
|
<view :style="levelStyle" class=" flex-shrink-0 flex flex-col items-center justify-center" @click="changeLevel(index)" :id="'id' + index">
|
||||||
|
<view class="w-[14rpx] h-[14rpx] level-class" :class="{'level-select': levelIndex == (index)}"></view>
|
||||||
|
<view :style="maxWidth" class="text-[24rpx] text-[#aaa] mt-[10rpx] truncate">{{item.level_name}}</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex mx-[30rpx] pt-[30rpx] pb-[46rpx] items-center flex-col level_benefits" v-if="currLevelInfo.benefits_arr && currLevelInfo.benefits_arr.length" :style="{ backgroundImage: 'url(' + img(currLevelInfo.member_bg) + ')'}">
|
||||||
|
<view class="flex items-center justify-center">
|
||||||
|
<text class="text-[#fff] text-[32rpx] font-bold leading-[44rpx]">会员权益</text>
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-wrap w-[690rpx] mt-[40rpx] justify-between">
|
||||||
|
<view class="flex flex-col w-[25%] items-center" v-for="(item,index) in currLevelInfo.benefits_arr" :key="index">
|
||||||
|
<image class="h-[100rpx] w-[100rpx]" :src="img(item.icon)" mode="heightFix" />
|
||||||
|
<text class="text-[rgba(255,255,255,0.9)] mt-[10rpx] text-[24rpx] leading-[34rpx]">{{item.title}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="flex-1 rounded-t-[40rpx] px-[30rpx] pt-[30rpx] mt-[-16rpx] relative tab-bar" :style="{background: `linear-gradient( 180deg, ${currLevelInfo.level_style.gift} 0%, #FFFFFF 20%)`}">
|
||||||
|
<!-- 升级礼包 -->
|
||||||
|
<view v-if="currLevelInfo.gifts_arr && currLevelInfo.gifts_arr.length">
|
||||||
|
<view class="pt-[10rpx] pb-[30rpx] flex items-center">
|
||||||
|
<text class="text-[32rpx] text-[#333] font-bold leading-[44rpx]">升级礼包</text>
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-wrap">
|
||||||
|
<view v-for="(item,index) in currLevelInfo.gifts_arr" :key="index" class="mb-[20rpx]" :class="{'mr-[20rpx]': (index+1) % 3 != 0}">
|
||||||
|
<view class="relative box-border mb-[12rpx] w-[216rpx] h-[180rpx] !bg-contain" :style="{ background: 'url(' + img(item.background) + ') no-repeat'}">
|
||||||
|
</view>
|
||||||
|
<view class="text-center text-[#333] text-[28rpx] font-500 truncate leading-[40rpx] max-w-[216rpx]">{{item.text}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 升级技巧 -->
|
||||||
|
<view v-if="upgradeSkills && upgradeSkills.length">
|
||||||
|
<view class="pt-[10rpx] pb-[30rpx] flex items-center">
|
||||||
|
<text class="text-[32rpx] text-[#333] font-bold leading-[44rpx]">升级技巧</text>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<view class="flex items-center mb-[30rpx]" v-for="(item,index) in upgradeSkills" :key="index">
|
||||||
|
<image class="h-[100rpx] w-[100rpx] mr-[20rpx]" :src="img(item.icon)" mode="heightFix" />
|
||||||
|
<view class="flex flex-col">
|
||||||
|
<view class="text-[#3A3945] text-[28rpx] font-bold leading-[38rpx] mb-[8rpx]">{{item.title}}</view>
|
||||||
|
<view class="text-[24rpx] text-[#3A3945] leading-[34rpx]">{{item.desc}}</view>
|
||||||
|
</view>
|
||||||
|
<text class="skill-btn" @click="redirect({ url: item.button.wap_redirect, param: {} , mode: 'redirectTo'})">{{item.button.text}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="!loading && (!list || !list.length)" class="h-[100vh] w-full flex items-center justify-center">
|
||||||
|
<u-empty :icon="img('static/resource/images/empty.png')" text="暂无会员等级" />
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed } from 'vue'
|
||||||
|
import { onShow } from '@dcloudio/uni-app'
|
||||||
|
import { getMemberLevel, getTaskGrowth } from '@/app/api/member';
|
||||||
|
import { img,redirect, deepClone, getToken } from '@/utils/common';
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import { topTabar } from '@/utils/topTabbar'
|
||||||
|
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const list = ref([]) // 会员等级
|
||||||
|
const upgradeSkills = ref([]) // 升级技巧
|
||||||
|
const swiperIndex = ref(0); //当前滑块的索引
|
||||||
|
const levelIndex = ref(0); //当前等级的索引
|
||||||
|
|
||||||
|
/********* 自定义头部 - start ***********/
|
||||||
|
const topTabarObj = topTabar()
|
||||||
|
let topTabbarData = topTabarObj.setTopTabbarParam({title:'会员等级'})
|
||||||
|
/********* 自定义头部 - end ***********/
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
// 判断是否已登录
|
||||||
|
if (getToken()) {
|
||||||
|
getTaskGrowthFn();
|
||||||
|
getMemberLevelFn();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 会员信息
|
||||||
|
const memberInfo = computed(() => {
|
||||||
|
return memberStore.info
|
||||||
|
})
|
||||||
|
|
||||||
|
// 进度条值
|
||||||
|
const progress = (index:any) => {
|
||||||
|
let indent = index;
|
||||||
|
let num = 100
|
||||||
|
if(list.value[indent] && list.value[indent].growth) {
|
||||||
|
num = memberInfo.value.growth / list.value[indent].growth * 100
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所需的成长值
|
||||||
|
const upgradeGrowth = (index:any) => {
|
||||||
|
let indent = index;
|
||||||
|
let num = 0;
|
||||||
|
if(list.value[indent] && list.value[indent].growth) {
|
||||||
|
num = list.value[indent].growth - memberInfo.value.growth;
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
const levelStyle = ref(''); // 等级样式
|
||||||
|
const maxWidth = ref(''); // 等级样式
|
||||||
|
const lineStyle = ref(''); // 线样式
|
||||||
|
const getMemberLevelFn = ()=>{
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
getMemberLevel().then((res) => {
|
||||||
|
list.value = res.data || [];
|
||||||
|
|
||||||
|
// 初始化会员等级数据
|
||||||
|
let bool = true;
|
||||||
|
if(memberInfo.value && list.value && list.value.length){
|
||||||
|
list.value.forEach((item,index)=>{
|
||||||
|
if(item.level_id == memberInfo.value.member_level){
|
||||||
|
bool = false;
|
||||||
|
swiperIndex.value = index;
|
||||||
|
levelIndex.value = swiperIndex.value;
|
||||||
|
infoStructureFn(index);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(bool) infoStructureFn(0);
|
||||||
|
if(list.value && list.value.length >= 5){
|
||||||
|
levelStyle.value ='width:115rpx;'
|
||||||
|
maxWidth.value = 'max-width:115rpx;'
|
||||||
|
lineStyle.value = `width:460rpx;transform: translateX(-235rpx);`
|
||||||
|
}else if(list.value && list.value.length == 4){
|
||||||
|
levelStyle.value ='width:144rpx;'
|
||||||
|
maxWidth.value = 'max-width:144rpx;'
|
||||||
|
lineStyle.value = `width:436rpx;transform: translateX(-218rpx);`
|
||||||
|
}else if(list.value && list.value.length == 3){
|
||||||
|
levelStyle.value ='width:192rpx;'
|
||||||
|
maxWidth.value = 'max-width:192rpx;'
|
||||||
|
lineStyle.value = `width:388rpx;transform: translateX(-194rpx);`
|
||||||
|
}else if(list.value && list.value.length == 2){
|
||||||
|
levelStyle.value ='width:289rpx;'
|
||||||
|
maxWidth.value = 'max-width:289rpx;'
|
||||||
|
lineStyle.value = `width:289rpx;transform: translateX(-144rpx);`
|
||||||
|
}else{
|
||||||
|
maxWidth.value = 'max-width:578rpx;'
|
||||||
|
levelStyle.value ='width:100%;'
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}).catch(()=>{
|
||||||
|
loading.value = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTaskGrowthFn = ()=>{
|
||||||
|
getTaskGrowth().then((res) => {
|
||||||
|
upgradeSkills.value = res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const swiperChange = (e) => {
|
||||||
|
swiperIndex.value = e.detail.current;
|
||||||
|
levelIndex.value = swiperIndex.value
|
||||||
|
infoStructureFn(e.detail.current);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当前的会员等级信息
|
||||||
|
const currLevelInfo = ref<any>({});
|
||||||
|
const infoStructureFn = (index:number)=>{
|
||||||
|
let data:any = deepClone(list.value[index]);
|
||||||
|
// 会员权益
|
||||||
|
if(data && data.level_benefits){
|
||||||
|
data.benefits_arr = [];
|
||||||
|
Object.values(data.level_benefits).forEach((item,index,Array)=>{
|
||||||
|
if(item.content){
|
||||||
|
data.benefits_arr.push(item.content)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 升级礼包
|
||||||
|
if(data && data.level_gifts){
|
||||||
|
data.gifts_arr = [];
|
||||||
|
for(let key in data.level_gifts){
|
||||||
|
if(data.level_gifts[key].content){
|
||||||
|
// 增加类型
|
||||||
|
data.level_gifts[key].content.forEach((item,index,Array)=>{
|
||||||
|
Array[index].type = key
|
||||||
|
})
|
||||||
|
data.gifts_arr = data.gifts_arr.concat(data.level_gifts[key].content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currLevelInfo.value = data;
|
||||||
|
}
|
||||||
|
// 改变会员等级
|
||||||
|
const changeLevel = (index : any) =>{
|
||||||
|
levelIndex.value = index;
|
||||||
|
swiperIndex.value = index;
|
||||||
|
infoStructureFn(index);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.skill-btn{
|
||||||
|
padding: 0 20rpx;
|
||||||
|
height: 54rpx;
|
||||||
|
line-height: 56rpx;
|
||||||
|
color: #333;
|
||||||
|
background: linear-gradient( 180deg, #FEE8AC 0%, #F5D36E 85%);
|
||||||
|
border-radius: 30rpx;
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
.swiper-animation{
|
||||||
|
transform: scale(0.92, 0.92);
|
||||||
|
transition-duration: 0.3s;
|
||||||
|
transition-timing-function: ease;
|
||||||
|
}
|
||||||
|
:deep(.uni-progress) .uni-progress-bar, :deep(.uni-progress) .uni-progress-inner-bar{
|
||||||
|
border-radius: 10rpx;
|
||||||
|
}
|
||||||
|
.tab-bar {
|
||||||
|
padding-bottom: constant(safe-area-inset-bottom);
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-class{
|
||||||
|
position: relative;
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 14rpx;
|
||||||
|
height: 14rpx;
|
||||||
|
background-color: #aaa;
|
||||||
|
border-radius: 14rpx;
|
||||||
|
top:50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%,-50%);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.level-select{
|
||||||
|
position: relative;
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 26rpx;
|
||||||
|
height: 26rpx;
|
||||||
|
background-color: #F6F6F6;
|
||||||
|
opacity: 0.4;
|
||||||
|
border-radius: 26rpx;
|
||||||
|
top:50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%,-50%);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.level_benefits{
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
247
uni-app/src/app/pages/member/location_address_edit.vue
Normal file
247
uni-app/src/app/pages/member/location_address_edit.vue
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<scroll-view scroll-y="true" class="bg-page h-screen">
|
||||||
|
<!-- <view class="h-[88rpx]">
|
||||||
|
<u-navbar title="添加地址" @rightClick="rightClick" :autoBack="true"></u-navbar>
|
||||||
|
</view> -->
|
||||||
|
<view class="h-[30rpx]"></view>
|
||||||
|
<view class="m-[30rpx] mt-0 p-[30rpx] pt-[10rpx] rounded-md bg-white">
|
||||||
|
<u-form labelPosition="left" :model="formData" labelWidth="200rpx" errorType='toast' :rules="rules" ref="formRef">
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('name')" prop="name" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.name" border="none" clearable maxlength="25" :placeholder="t('namePlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('mobile')" prop="mobile" :border-bottom="true">
|
||||||
|
<u-input v-model="formData.mobile" border="none" clearable :placeholder="t('mobilePlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('deliveryAddress')" prop="address_name" :border-bottom="true">
|
||||||
|
<view class="flex justify-between flex-1" @click="chooseLocation">
|
||||||
|
<view class="text-[15px]" :class="{ 'text-[#303133]': formData.area,'text-[#c3c4d5]':!formData.area }">{{formData.area ? formData.address_name : t('selectAddressPlaceholder')}}</view>
|
||||||
|
<u-icon name="arrow-right" color="#c3c4d5"></u-icon>
|
||||||
|
</view>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('address')" prop="address" :border-bottom="true">
|
||||||
|
<u-input v-model.trim="formData.address" border="none" clearable maxlength="120" :placeholder="t('addressPlaceholder')"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<u-form-item :label="t('defaultAddress')" prop="name" :border-bottom="true" >
|
||||||
|
<u-switch v-model="formData.is_default" size="20" :activeValue="1" :inactiveValue="0" activeColor="var(--primary-color)"/>
|
||||||
|
</u-form-item>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[40rpx]">
|
||||||
|
<button class="!bg-[var(--primary-color)] !text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" :class="{'opacity-50': btnDisabled}" @click="save" :disabled="btnDisabled" :loading="operateLoading">{{t('save')}}</button>
|
||||||
|
</view>
|
||||||
|
</u-form>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { redirect } from '@/utils/common'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { addAddress, editAddress, getAddressInfo } from '@/app/api/member'
|
||||||
|
import manifestJson from '@/manifest.json'
|
||||||
|
import { getAddressByLatlng } from '@/app/api/system'
|
||||||
|
|
||||||
|
const type = ref('')
|
||||||
|
const source = ref('')
|
||||||
|
const btnDisabled = ref(false)
|
||||||
|
|
||||||
|
const formData = ref({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
mobile: '',
|
||||||
|
province_id: 0,
|
||||||
|
city_id: 0,
|
||||||
|
district_id: 0,
|
||||||
|
lat: '',
|
||||||
|
lng: '',
|
||||||
|
address: '',
|
||||||
|
address_name: '',
|
||||||
|
full_address: '',
|
||||||
|
is_default: 0,
|
||||||
|
area: '',
|
||||||
|
type: 'location_address'
|
||||||
|
})
|
||||||
|
|
||||||
|
onLoad((option:any) => {
|
||||||
|
if (option.id) {
|
||||||
|
getAddressInfo(option.id).then(({ data }) => {
|
||||||
|
if (data) {
|
||||||
|
Object.assign(formData.value, data)
|
||||||
|
formData.value.area = formData.value.full_address.replace(formData.value.address, '').replace(formData.value.address_name, '')
|
||||||
|
}
|
||||||
|
}).catch()
|
||||||
|
} else if (option.name) {
|
||||||
|
if (uni.getStorageSync('addressInfo')) {
|
||||||
|
Object.assign(formData.value, uni.getStorageSync('addressInfo'))
|
||||||
|
}
|
||||||
|
formData.value.address = option.name;
|
||||||
|
getAddress(option.latng);
|
||||||
|
var tempArr = getQueryVariable('latng').split(',');
|
||||||
|
formData.value.lat = tempArr[0];
|
||||||
|
formData.value.lng = tempArr[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
type.value = option.type || ''
|
||||||
|
source.value = option.source || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRef = ref(null)
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
'address': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: t('addressError'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
message: t('namePlaceholder'),
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
},
|
||||||
|
'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(t('mobileError')))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getQueryVariable = (variable:any)=> {
|
||||||
|
var query = window.location.search.substring(1);
|
||||||
|
var vars = query.split('&');
|
||||||
|
for (var i = 0; i < vars.length; i++) {
|
||||||
|
var pair = vars[i].split('=');
|
||||||
|
if (pair[0] == variable) {
|
||||||
|
return pair[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取详细地址
|
||||||
|
const getAddress = (latlng:any)=> {
|
||||||
|
getAddressByLatlng({latlng}).then((res: any) => {
|
||||||
|
if (res.data) {
|
||||||
|
formData.value.full_address = '';
|
||||||
|
formData.value.full_address += res.data.province != undefined ? res.data.province : '';
|
||||||
|
formData.value.full_address += res.data.city != undefined ? '' + res.data.city : '';
|
||||||
|
formData.value.full_address += res.data.district != undefined ? '' + res.data.district : '';
|
||||||
|
|
||||||
|
formData.value.address_name = formData.value.full_address.replace(/-/g,'');
|
||||||
|
formData.value.area = res.data.full_address;
|
||||||
|
|
||||||
|
formData.value.province_id = res.data.province_id != undefined ? res.data.province_id : 0;
|
||||||
|
formData.value.city_id = res.data.city_id != undefined ? res.data.city_id : 0;
|
||||||
|
formData.value.district_id = res.data.district_id != undefined ? res.data.district_id : 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
uni.showToast({title: res.msg, icon: 'none'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const operateLoading = ref(false)
|
||||||
|
const save = ()=> {
|
||||||
|
if (uni.$u.test.isEmpty(formData.value.area)) {
|
||||||
|
uni.showToast({title: t('selectAddressPlaceholder'), icon: 'none'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const save = formData.value.id ? editAddress : addAddress
|
||||||
|
|
||||||
|
formRef.value.validate().then(() => {
|
||||||
|
if (operateLoading.value) return
|
||||||
|
operateLoading.value = true
|
||||||
|
|
||||||
|
btnDisabled.value = true
|
||||||
|
|
||||||
|
formData.value.full_address = `${formData.value.area}${formData.value.address_name}${formData.value.address}`
|
||||||
|
|
||||||
|
save(formData.value).then((res) => {
|
||||||
|
operateLoading.value = false
|
||||||
|
uni.removeStorageSync('addressInfo');
|
||||||
|
setTimeout(() => {
|
||||||
|
btnDisabled.value = false
|
||||||
|
redirect({
|
||||||
|
url: '/app/pages/member/address',
|
||||||
|
mode: 'redirectTo',
|
||||||
|
param: {type: type.value, source: source.value}
|
||||||
|
})
|
||||||
|
}, 1000)
|
||||||
|
}).catch(() => {
|
||||||
|
operateLoading.value = false
|
||||||
|
btnDisabled.value = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const chooseLocation = ()=> {
|
||||||
|
// #ifdef MP
|
||||||
|
uni.chooseLocation({
|
||||||
|
success: (res) => {
|
||||||
|
res.latitude && (formData.value.lat = res.latitude)
|
||||||
|
res.longitude && (formData.value.lng = res.longitude)
|
||||||
|
res.address && (formData.value.area = res.address)
|
||||||
|
res.name && (formData.value.address_name = res.name)
|
||||||
|
},
|
||||||
|
fail: (res)=>{
|
||||||
|
// 在隐私协议中没有声明chooseLocation:fail api作用域
|
||||||
|
if(res.errMsg && res.errno) {
|
||||||
|
if(res.errno == 104){
|
||||||
|
let msg = '用户未授权隐私权限,选择位置失败';
|
||||||
|
uni.showToast({title: msg, icon: 'none'})
|
||||||
|
}else if(res.errno == 112){
|
||||||
|
let msg = '隐私协议中未声明,打开地图选择位置失败';
|
||||||
|
uni.showToast({title: msg, icon: 'none'})
|
||||||
|
}else {
|
||||||
|
uni.showToast({title: res.errMsg, icon: 'none'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
var urlencode = formData.value;
|
||||||
|
uni.setStorageSync('addressInfo', urlencode);
|
||||||
|
let backurl = location.origin + location.pathname + '?type=' + type.value + '&source=' + source.value;
|
||||||
|
window.location.href = 'https://apis.map.qq.com/tools/locpicker?search=1&type=0&backurl=' + encodeURIComponent(backurl) + '&key=' + manifestJson.h5.sdkConfigs.maps.qqmap.key + '&referer=myapp';
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
209
uni-app/src/app/pages/member/personal.vue
Normal file
209
uni-app/src/app/pages/member/personal.vue
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-full h-screen bg-page personal-wrap" v-if="info" :style="themeColor()">
|
||||||
|
<view class="flex flex-col items-center pt-[30rpx]">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<button open-type="chooseAvatar" @chooseavatar="onChooseAvatar" :plain="true" class="border-0" @click="checkWxPrivacy">
|
||||||
|
<u-avatar :src="img(info.headimg)" :default-url="img('static/resource/images/default_headimg.png')" size="60" leftIcon="none"></u-avatar>
|
||||||
|
<view class="text-primary text-sm mt-[10rpx]">{{ t('updateHeadimg') }}</view>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
|
<u-upload @afterRead="afterRead" :maxCount="1">
|
||||||
|
<u-avatar :src="img(info.headimg)" :default-url="img('static/resource/images/default_headimg.png')" size="60" leftIcon="none"></u-avatar>
|
||||||
|
<view class="text-primary text-sm mt-[10rpx]">{{ t('updateHeadimg') }}</view>
|
||||||
|
</u-upload>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="m-[30rpx] bg-white rounded-md overflow-hidden px-[20rpx] py-[10rpx]">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<u-cell :title="t('nickname')" :is-link="true" :value="info.nickname" @click="updateNickname.modal = true"></u-cell>
|
||||||
|
<u-cell :title="t('sex')" :is-link="true" :value="info.sex_name || t('unknown')" @click="sexSheetShow = true"></u-cell>
|
||||||
|
<u-cell :title="t('mobile')">
|
||||||
|
<template #value>
|
||||||
|
<view v-if="info.mobile" class="mr-[10rpx]">{{ mobileConceal(info.mobile) }}</view>
|
||||||
|
<view v-else @click="redirect({ url: '/app/pages/auth/bind' })">
|
||||||
|
<button class="bg-transparent w-[132rpx] p-[0] rounded-[100rpx] text-[var(--primary-color)] !border-[2rpx] !border-solid border-[var(--primary-color)] text-[20rpx] h-[44rpx] leading-[40rpx]">{{t('bindMobile')}}</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</u-cell>
|
||||||
|
<u-cell :title="t('birthday')" :is-link="true" :value="formatDate(info.birthday) || t('unknown')" @click="birthdayPicker = true"></u-cell>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<u-modal :show="updateNickname.modal" :closeOnClickOverlay="true" @close="updateNickname.modal = false"
|
||||||
|
:show-cancel-button="true"
|
||||||
|
@cancel="updateNickname.modal = false" :title="t('updateNickname')" confirmColor="var(--primary-color)">
|
||||||
|
<view class="w-full mt-[20rpx] border-0 border-b border-gray-300 border-solid py-[20rpx]">
|
||||||
|
<input type="nickname" v-model="updateNickname.value" :placeholder="t('nicknamePlaceholder')" @blur="bindNickname">
|
||||||
|
</view>
|
||||||
|
<template #confirmButton>
|
||||||
|
<view class="mt-[10rpx]">
|
||||||
|
<button class="bg-[var(--primary-color)] text-[#fff] h-[80rpx] leading-[80rpx] rounded-[100rpx] text-[28rpx]" @click="updateNicknameConfirm">{{t('confirm')}}</button>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
</u-modal>
|
||||||
|
|
||||||
|
<u-action-sheet :actions="sexList" :show="sexSheetShow" :closeOnClickOverlay="true"
|
||||||
|
:safeAreaInsetBottom="true"
|
||||||
|
@close="sexSheetShow = false" @select="updateSex"></u-action-sheet>
|
||||||
|
|
||||||
|
<u-datetime-picker v-model="info.birthday" :show="birthdayPicker" mode="date" :confirm-text="t('confirm')"
|
||||||
|
:maxDate="new Date().valueOf()" :minDate="0"
|
||||||
|
:cancel-text="t('cancel')" @cancel="birthdayPicker = false" @confirm="updateBirthday"></u-datetime-picker>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<wx-privacy-popup ref="wxPrivacyPopupRef"></wx-privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, reactive } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import { img, redirect,mobileConceal } from '@/utils/common'
|
||||||
|
import { modifyMember } from '@/app/api/member'
|
||||||
|
import { fetchBase64Image, uploadImage } from '@/app/api/system'
|
||||||
|
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
const info = computed(() => memberStore.info)
|
||||||
|
|
||||||
|
|
||||||
|
const wxPrivacyPopupRef:any = ref(null)
|
||||||
|
|
||||||
|
// 检测是否同意隐私协议
|
||||||
|
const checkWxPrivacy = ()=>{
|
||||||
|
wxPrivacyPopupRef.value.proactive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改昵称
|
||||||
|
*/
|
||||||
|
const updateNickname = reactive({
|
||||||
|
modal: false,
|
||||||
|
value: info.nickname || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const bindNickname = (e) => {
|
||||||
|
updateNickname.value = e.detail.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateNicknameConfirm = () => {
|
||||||
|
if (uni.$u.test.isEmpty(updateNickname.value)) { uni.showToast({ title: t('nicknamePlaceholder'), icon: 'none' }); return }
|
||||||
|
|
||||||
|
modifyMember({
|
||||||
|
field: 'nickname',
|
||||||
|
value: updateNickname.value
|
||||||
|
}).then(res => {
|
||||||
|
memberStore.info.nickname = updateNickname.value
|
||||||
|
updateNickname.modal = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改性别
|
||||||
|
*/
|
||||||
|
const sexSheetShow = ref(false)
|
||||||
|
const sexList = computed(() => {
|
||||||
|
return [
|
||||||
|
{ name: t('man'), value: 1 },
|
||||||
|
{ name: t('woman'), value: 2 }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const updateSex = (e) => {
|
||||||
|
modifyMember({
|
||||||
|
field: 'sex',
|
||||||
|
value: e.value
|
||||||
|
}).then(res => {
|
||||||
|
memberStore.info.sex_name = e.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户头像
|
||||||
|
*/
|
||||||
|
const onChooseAvatar = (e) => {
|
||||||
|
uni.getFileSystemManager().readFile({
|
||||||
|
filePath: e.detail.avatarUrl, //选择图片返回的相对路径
|
||||||
|
encoding: 'base64', //编码格式
|
||||||
|
success: res => {
|
||||||
|
fetchBase64Image({ content: res.data }).then(uploadRes => {
|
||||||
|
modifyMember({
|
||||||
|
field: 'headimg',
|
||||||
|
value: uploadRes.data.url
|
||||||
|
}).then(res => {
|
||||||
|
memberStore.info.headimg = uploadRes.data.url
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const afterRead = (event) => {
|
||||||
|
uploadImage({
|
||||||
|
filePath: event.file.url,
|
||||||
|
name: 'file'
|
||||||
|
}).then(res => {
|
||||||
|
modifyMember({
|
||||||
|
field: 'headimg',
|
||||||
|
value: res.data.url
|
||||||
|
}).then(() => {
|
||||||
|
memberStore.info.headimg = res.data.url
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑生日
|
||||||
|
*/
|
||||||
|
const birthdayPicker = ref(false)
|
||||||
|
const updateBirthday = (e) => {
|
||||||
|
modifyMember({
|
||||||
|
field: 'birthday',
|
||||||
|
value: uni.$u.date(e.value, 'yyyy-mm-dd')
|
||||||
|
}).then(() => {
|
||||||
|
memberStore.info.birthday = uni.$u.date(e.value || e.value + 1, 'yyyy-mm-dd')
|
||||||
|
birthdayPicker.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const formatDate=(date:any)=>{
|
||||||
|
return date ? uni.$u.date(new Date(date), 'yyyy-mm-dd') : ''
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background: var(--page-bg-color);
|
||||||
|
}
|
||||||
|
:deep(.u-upload__wrap ){
|
||||||
|
>view{
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
:deep(.u-cell-group__wrapper) {
|
||||||
|
.u-cell__body {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell {
|
||||||
|
&:last-child .u-line {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(button, button:after) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style lang="scss">
|
||||||
|
.personal-wrap .u-cell--clickable{
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
170
uni-app/src/app/pages/member/point.vue
Normal file
170
uni-app/src/app/pages/member/point.vue
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<template>
|
||||||
|
<view class="bg-[#F6F6F6] min-h-[100vh]" :style="themeColor()">
|
||||||
|
<template v-if="!loading">
|
||||||
|
<view class="w-full bg-[#F6F6F6]">
|
||||||
|
<view class="pb-[210rpx] relative" :style="headerStyle">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<top-tabbar :data="param" :scrollBool="topTabarObj.getScrollBool()" class="top-header"/>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="text-[70rpx] leading-[98rpx] text-[#fff] pl-[60rpx] font-600 pt-[77rpx]">{{pointInfo.point||0}}</view>
|
||||||
|
<view class="flex items-center pl-[60rpx]">
|
||||||
|
<image class="h-[36rpx] w-[36rpx]" :src="img('static/resource/images/member/point/icon.png')" mode="heightFix" />
|
||||||
|
<view class="text-[26rpx] leading-[36rpx] text-[#fff] ml-[10rpx]">我的积分</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center absolute right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[50rpx] z-10" :style="{top: topStyle}" @click="toLink('/app/pages/member/point_detail')">
|
||||||
|
<text class="nc-iconfont nc-icon-jifenduihuanV6xx1 text-[28rpx] text-[#fff] mr-[10rpx]"></text>
|
||||||
|
<text class="text-[24rpx]">积分明细</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="sidebar-marign flex flex-col mt-[-178rpx] relative">
|
||||||
|
<view class="w-[322rpx] h-[80rpx] leading-[80rpx] text-[26rpx] text-[#333] font-bold box-border pl-[30rpx]"
|
||||||
|
:style="{backgroundImage: 'url(' + img('static/resource/images/member/point/top_bg.png') + ') ',backgroundSize: '100% 100%',backgroundRepeat: 'no-repeat'}">
|
||||||
|
积分详情
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center px-[30rpx] rounded-[16rpx] !rounded-tl-none bg-[#fff] h-[173rpx] box-border">
|
||||||
|
<view class="w-[196rpx] flex-shrink-0 text-center">
|
||||||
|
<view class="text-[#333] text-[42rpx] leading-[59rpx] font-bold">{{pointInfo.point_get||0}}</view>
|
||||||
|
<view class="mt-[8rpx] text-[#666] text-[26rpx] leading-[36rpx] font-400">累计积分</view>
|
||||||
|
</view>
|
||||||
|
<view class="w-[1rpx] h-[50rpx] flex-shrink-0 bg-[#EBEBEB] mx-[10rpx]"></view>
|
||||||
|
<view class="w-[196rpx] flex-shrink-0 text-center">
|
||||||
|
<view class="text-[#333] text-[42rpx] leading-[59rpx] font-bold">{{pointInfo.use||0}}</view>
|
||||||
|
<view class="mt-[8rpx] text-[#666] text-[26rpx] leading-[36rpx] font-400">累计消费</view>
|
||||||
|
</view>
|
||||||
|
<view class="w-[1rpx] h-[50rpx] flex-shrink-0 bg-[#EBEBEB] mx-[10rpx]"></view>
|
||||||
|
<view class="w-[196rpx] min-w-[209.33rpx] flex-shrink-0 text-center">
|
||||||
|
<view class="text-[#333] text-[42rpx] leading-[59rpx] font-bold">{{pointInfo.point||0}}</view>
|
||||||
|
<view class="mt-[8rpx] text-[#666] text-[26rpx] leading-[36rpx] font-400">可用积分</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[20rpx] sidebar-marign p-[30rpx] pb-[70rpx] box-border rounded-[16rpx] bg-[#fff]">
|
||||||
|
<view class="text-[32rpx] leading-[45rpx] font-bold">热门活动</view>
|
||||||
|
<view class="mt-[50rpx] flex justify-between">
|
||||||
|
<view class="w-[200rpx] h-[253rpx] box-border pt-[69rpx] relative text-center"
|
||||||
|
:style="{backgroundImage: 'url(' + img('static/resource/images/member/point/activity_1.png') + ') ',
|
||||||
|
backgroundSize: '100% 100%',
|
||||||
|
backgroundRepeat: 'no-repeat'}">
|
||||||
|
<image class="h-[78rpx] w-[78rpx] absolute left-[65rpx] top-[-21rpx]" :src="img('static/resource/images/member/point/activity_icon_1.png')" mode="heightFix" />
|
||||||
|
<view class="text-[28rpx] leading-[39rpx] text-[#333]">每日赚积分</view>
|
||||||
|
<view class="mt-[10rpx] text-[24rpx] leading-[34rpx] text-[#999] font-500">每日签到</view>
|
||||||
|
<view class="w-full flex justify-center mt-[20rpx]">
|
||||||
|
<button class="h-[40rpx] !m-0 rounded-[40rpx] text-[26rpx] leading-[40rpx] !text-[#fff] !" shape="circle"
|
||||||
|
:style="{background: 'linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C'}" @click="toLink('/app/pages/member/sign_in')">去签到</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="w-[200rpx] h-[253rpx] box-border pt-[69rpx] relative text-center"
|
||||||
|
:style="{backgroundImage: 'url(' + img('static/resource/images/member/point/activity_2.png') + ') ',
|
||||||
|
backgroundSize: '100% 100%',
|
||||||
|
backgroundRepeat: 'no-repeat'}">
|
||||||
|
<image class="h-[78rpx] w-[78rpx] absolute left-[65rpx] top-[-21rpx]" :src="img('static/resource/images/member/point/activity_icon_2.png')" mode="heightFix" />
|
||||||
|
<view class="text-[28rpx] leading-[39rpx] text-[#333]">积分当钱花</view>
|
||||||
|
<view class="mt-[10rpx] text-[24rpx] leading-[34rpx] text-[#999] font-500">抵扣部分费用</view>
|
||||||
|
<view class="w-full flex justify-center mt-[20rpx]">
|
||||||
|
<button class="h-[40rpx] !m-0 rounded-[40rpx] text-[26rpx] leading-[40rpx] !text-[#fff] !" shape="circle"
|
||||||
|
:style="{background: 'linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C'}" @click="toLink('/addon/shop/pages/point/index')">去兑换</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="w-[200rpx] h-[253rpx] box-border pt-[69rpx] relative text-center"
|
||||||
|
:style="{backgroundImage: 'url(' + img('static/resource/images/member/point/activity_3.png') + ') ',
|
||||||
|
backgroundSize: '100% 100%',
|
||||||
|
backgroundRepeat: 'no-repeat'}">
|
||||||
|
<image class="h-[78rpx] w-[78rpx] absolute left-[65rpx] top-[-21rpx]" :src="img('static/resource/images/member/point/icon.png')" mode="heightFix" />
|
||||||
|
<view class="text-[28rpx] leading-[39rpx] text-[#333]">购物返积分</view>
|
||||||
|
<view class="mt-[10rpx] text-[24rpx] leading-[34rpx] text-[#999] font-500">下单得积分</view>
|
||||||
|
<view class="w-full flex justify-center mt-[20rpx]">
|
||||||
|
<button class="h-[40rpx] !m-0 rounded-[40rpx] text-[26rpx] leading-[40rpx] !text-[#fff] !" shape="circle"
|
||||||
|
:style="{background: 'linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C'}" @click="toLink('/addon/shop/pages/goods/list')">去逛逛</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="mt-[20rpx] mx-[30rpx] p-[30rpx] box-border rounded-[16rpx] bg-[#fff]" v-if="pointList.length">
|
||||||
|
<view class="flex justify-between items-center">
|
||||||
|
<view class="text-[32rpx] leading-[45rpx] font-bold">做任务领积分</view>
|
||||||
|
<!-- <view class="flex items-center text-[#666]">
|
||||||
|
<text class=" text-[26rpx] leading-[36rpx] mr-[10rpx]">更多</text>
|
||||||
|
<text class=" text-[18rpx] leading-[36rpx] iconfont iconxiayibu1 text-[#999]"></text>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
<block v-for="(item,index) in pointList">
|
||||||
|
<view class="flex items-center justify-between mt-[30rpx]">
|
||||||
|
<view class="flex items-center flex-1">
|
||||||
|
<image class="h-[62rpx] w-[62rpx]" :src="img(item.icon||'')" mode="heightFix" />
|
||||||
|
<view class="flex flex-col ml-[20rpx]">
|
||||||
|
<view class="flex">
|
||||||
|
<text class="text-[28rpx] leading-[39rpx]">{{item.title}}</text>
|
||||||
|
<!-- <image class="h-[28rpx] w-[28rpx] ml-[10rpx] mr-[6rpx]" :src="img('static/resource/images/member/point/icon.png')" mode="heightFix" /> -->
|
||||||
|
<!-- <text class="text-[#EF000C] text-[28rpx] leading-[39rpx]">+10</text> -->
|
||||||
|
</view>
|
||||||
|
<view class="mt-[10rpx] text-[#999] text-[24rpx] leading-[34rpx] font-400">{{item.desc}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<button v-if="item.button" class="h-[56rpx] !m-0 rounded-[40rpx] text-[26rpx] leading-[56rpx] !text-[#fff] !" shape="circle"
|
||||||
|
:style="{background: 'linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C'}" @click="toLink(item.button.wap_redirect)">{{item.button.text}}</button>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { redirect, img,pxToRpx } from '@/utils/common';
|
||||||
|
import { getMemberAccountPointcount,getTaskPoint } from '@/app/api/member';
|
||||||
|
import { topTabar } from '@/utils/topTabbar'
|
||||||
|
|
||||||
|
/********* 自定义头部 - start ***********/
|
||||||
|
const topTabarObj = topTabar()
|
||||||
|
let param = topTabarObj.setTopTabbarParam({title:'我的积分'})
|
||||||
|
/********* 自定义头部 - end ***********/
|
||||||
|
|
||||||
|
// 获取系统状态栏的高度
|
||||||
|
let menuButtonInfo:any = {};
|
||||||
|
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
|
||||||
|
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||||
|
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
|
||||||
|
// #endif
|
||||||
|
const headerStyle = computed(()=>{
|
||||||
|
return {
|
||||||
|
backgroundImage: 'url(' + img('static/resource/images/member/point/point_bg.png') + ') ',
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'bottom',
|
||||||
|
// paddingTop:Object.keys(menuButtonInfo).length?(Number(menuButtonInfo.height) * 2 + menuButtonInfo.top * 2 + 77)+'rpx':'77rpx',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const topStyle = computed(() => {
|
||||||
|
let style = ''
|
||||||
|
style = Object.keys(menuButtonInfo).length?(pxToRpx(Number(menuButtonInfo.height)) + pxToRpx(menuButtonInfo.top) + 38) + 'rpx;':'38rpx'
|
||||||
|
return style
|
||||||
|
})
|
||||||
|
|
||||||
|
//个人积分信息
|
||||||
|
const pointInfo = ref({});
|
||||||
|
//积分任务
|
||||||
|
const pointList = ref([]);
|
||||||
|
const loading = ref(true)
|
||||||
|
onLoad(async()=>{
|
||||||
|
let pointInfoRes :any = await getMemberAccountPointcount()
|
||||||
|
let pointListRes :any = await getTaskPoint()
|
||||||
|
pointInfo.value = pointInfoRes.data
|
||||||
|
pointList.value = pointListRes.data
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
const toLink=(url='',param={})=>{
|
||||||
|
redirect({ url, param })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bg-color{
|
||||||
|
background-color: rgba(102,102,102,0.4);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
165
uni-app/src/app/pages/member/point_detail.vue
Normal file
165
uni-app/src/app/pages/member/point_detail.vue
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<template>
|
||||||
|
<view class="bg-[#F6F6F6] min-h-[100vh]" :style="themeColor()">
|
||||||
|
<view class="fixed left-0 right-0 top-0 z-10085">
|
||||||
|
<view class="bg-[#fff] px-[var(--sidebar-m)] py-[14rpx] relative z-10084">
|
||||||
|
<view class="flex items-center h-[60rpx] bg-[#F8F9FD] rounded-[30rpx] px-[20rpx]">
|
||||||
|
<view class="flex-1 text-[26rpx] leading-[60rpx] text-[#8288A2]" :class="{'!text-[#333]':from_type}" @click="typePopup = true">{{from_type_name || '请选择来源用途'}}</view>
|
||||||
|
<text class="nc-iconfont nc-icon-shangV6xx-1 text-[32rpx] ml-[18rpx] !text-[#626779]" v-if="typePopup" @click="typePopup = false"></text>
|
||||||
|
<text class="nc-iconfont nc-icon-xiaV6xx text-[32rpx] ml-[18rpx] !text-[#626779]" v-else @click="typePopup = true"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<u-popup :show="typePopup" mode="top" @close="typePopup = false" class="type-class">
|
||||||
|
<view @touchmove.prevent.stop class="py-[22rpx]">
|
||||||
|
<view class="leading-[80rpx] text-[26rpx] text-[#333] px-[50rpx]" :class="{'bg-[#FDF8F8] !text-primary font-500' : from_type == ''}" @click="searchTypeFn()">全部</view>
|
||||||
|
<view class="leading-[80rpx] text-[26rpx] text-[#333] px-[50rpx]" :class="{'bg-[#FDF8F8] !text-primary font-500' : from_type == index}" v-for="(item,index) in pointType" @click="searchTypeFn(index,item)">{{ item.name }}</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
<view class="px-[var(--sidebar-m)] pt-[30rpx] pb-[20rpx] flex items-center justify-between bg-[#F6F6F6]">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="px-[20rpx] py-[6rpx] bg-[#fff] rounded-[30rpx] text-[26rpx] leading-[36rpx] mr-[20rpx] text-[#333]" :class="{'!text-[var(--primary-color)] font-500':amount_type == item.status}" v-for="(item,index) in typeList" :key="index" @click="loadTypeFn(item.status)">{{ item.name }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center" @click="handleSelect">
|
||||||
|
<view class="text-[26rpx] text-[#333] mr-[10rpx]">日期</view>
|
||||||
|
<view class="nc-iconfont nc-icon-riliV6xx !text-[28rpx] leading-[36rpx]"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-body ref="mescrollRef" @init="mescrollInit" :down="{ use: false }" @up="getPointListFn" top="186rpx">
|
||||||
|
<view v-for="(item,index) in pointList" :key="index" class="bg-white sidebar-marign rounded-[16rpx] px-[30rpx] mb-[20rpx] py-[12rpx]">
|
||||||
|
<view class="flex justify-between items-center">
|
||||||
|
<view class="text-[20rpx] text-[#333] font-500">
|
||||||
|
<text>{{item.month_info.year}}年</text>
|
||||||
|
<text class="text-[36rpx] font-bold ml-[10rpx] mr-[4rpx]">{{item.month_info.month}}</text>
|
||||||
|
<text>月</text>
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<text class="nc-iconfont nc-icon-xiaV6xx !text-[32rpx] text-[#626779]" v-if="item.flag" @click="item.flag = false"></text>
|
||||||
|
<text class="nc-iconfont nc-icon-shangV6xx-1 !text-[32rpx] text-[#626779]" v-else @click="item.flag = true"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-show="item.flag">
|
||||||
|
<block v-for="(subItem,subIndex) in item.month_data" :key="subItem.id">
|
||||||
|
<view class="flex items-center ">
|
||||||
|
<view class="w-[60rpx] h-[60rpx]">
|
||||||
|
<image v-if="subItem.account_data > 0" :src="img('static/resource/images/member/point/detail/point_add.png')" class="w-[60rpx] h-[60rpx]"></image>
|
||||||
|
<image v-else :src="img('static/resource/images/member/point/detail/point_min.png')" class="w-[60rpx] h-[60rpx]"></image>
|
||||||
|
</view>
|
||||||
|
<view class="flex-1 flex items-center ml-[20rpx] box-border py-[20rpx] border-0" :class="{'border-solid border-t-[2rpx] border-[#F0F2F8]' : subIndex}">
|
||||||
|
<view class="flex-1">
|
||||||
|
<view class="text-[26rpx] font-500 leading-[36rpx] text-[#333]">{{subItem.from_type_name}}</view>
|
||||||
|
<view class="text-[24rpx] text-[#8288A2] leading-[34rpx] mt-[4rpx]">{{subItem.create_time}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="text-[36rpx] font-500 text-[#03B521]" :class="{ '!text-primary' : subItem.account_data > 0 }">{{subItem.account_data > 0 ? '+' + subItem.account_data : subItem.account_data}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mx-[30rpx] rounded-[16rpx] noData flex items-center justify-center" v-if="!pointList.length && loading">
|
||||||
|
<mescroll-empty :option="{tip : '暂无积分明细'}"></mescroll-empty>
|
||||||
|
</view>
|
||||||
|
</mescroll-body>
|
||||||
|
<!-- 时间选择 -->
|
||||||
|
<select-date ref="selectDateRef" @confirm="confirmFn" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { redirect, img } from '@/utils/common';
|
||||||
|
import { getPointList, getPointType } from '@/app/api/member';
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
|
||||||
|
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app';
|
||||||
|
import selectDate from '@/components/select-date/select-date.vue';
|
||||||
|
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
|
||||||
|
|
||||||
|
const from_type = ref('');
|
||||||
|
const from_type_name = ref('')
|
||||||
|
const amount_type = ref('all');
|
||||||
|
const create_time = ref([])
|
||||||
|
const pointList = ref<Array<any>>([]);
|
||||||
|
const mescrollRef = ref(null);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const typeList = ref([
|
||||||
|
{name:'全部',status:'all'},
|
||||||
|
{name:'收入',status:'income'},
|
||||||
|
{name:'支出',status:'disburse'}
|
||||||
|
])
|
||||||
|
|
||||||
|
const getPointListFn = (mescroll)=> {
|
||||||
|
let data = {
|
||||||
|
page: mescroll.num,
|
||||||
|
page_size: mescroll.size,
|
||||||
|
from_type:from_type.value,
|
||||||
|
amount_type:amount_type.value,
|
||||||
|
create_time: create_time.value
|
||||||
|
};
|
||||||
|
loading.value = false;
|
||||||
|
getPointList(data).then((res) => {
|
||||||
|
let newArr = res.data.data;
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1) {
|
||||||
|
pointList.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
pointList.value = pointList.value.concat(newArr);
|
||||||
|
pointList.value = pointList.value.map(item =>{
|
||||||
|
item.flag = true
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
loading.value = true;
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = true;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const pointType = ref({})
|
||||||
|
const getPointTypeFn = () =>{
|
||||||
|
getPointType('point').then(res =>{
|
||||||
|
pointType.value = res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getPointTypeFn()
|
||||||
|
// 关键词搜索条件搜索
|
||||||
|
const typePopup = ref(false)
|
||||||
|
const searchTypeFn = (index:string = '',item:any = {}) =>{
|
||||||
|
from_type.value = index
|
||||||
|
from_type_name.value = item.name
|
||||||
|
typePopup.value = false
|
||||||
|
pointList.value = [];
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
// 类型搜索
|
||||||
|
const loadTypeFn = (type:string) =>{
|
||||||
|
amount_type.value = type;
|
||||||
|
pointList.value = [];
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
//日期筛选
|
||||||
|
const selectDateRef = ref()
|
||||||
|
const handleSelect = () =>{
|
||||||
|
selectDateRef.value.show = true
|
||||||
|
}
|
||||||
|
// 确定时间筛选
|
||||||
|
const confirmFn = (data:any) =>{
|
||||||
|
create_time.value = data;
|
||||||
|
pointList.value = []
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.u-popup.type-class .u-transition) {
|
||||||
|
top: 88rpx !important;
|
||||||
|
box-shadow: 1rpx 1rpx 6rpx 2rpx rgba(184,201,212,0.25);
|
||||||
|
}
|
||||||
|
.noData{
|
||||||
|
height: calc(100vh - 206rpx - constant(safe-area-inset-bottom));
|
||||||
|
height: calc(100vh - 206rpx - env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
488
uni-app/src/app/pages/member/sign_in.vue
Normal file
488
uni-app/src/app/pages/member/sign_in.vue
Normal file
@ -0,0 +1,488 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<view class="bg-[#F6F6F6] min-h-screen overflow-hidden" v-if="Object.values(info).length">
|
||||||
|
<view v-if="info.is_use">
|
||||||
|
<view class="sigin-header">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<view class="flex items-center absolute right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[40rpx] z-10" :style="{top: topStyle}" @click="signPopup = true">
|
||||||
|
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[6rpx]"></text>
|
||||||
|
<text class="text-[24rpx]">签到规则</text>
|
||||||
|
</view>
|
||||||
|
<view :style="{height: headStyle, backgroundImage: 'url(' + img('static/resource/images/app/sigin_uniapp.png') + ')',backgroundSize: '100% 100%', backgroundRepeat: 'no-repeat'}">
|
||||||
|
<top-tabbar :data="topTabbarData" :scrollBool="topTabarObj.getScrollBool()" class="top-header" />
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view v-if="info.rule_explain" class="flex items-center absolute top-[44rpx] right-0 px-[14rpx] bg-color rounded-l-[35rpx] text-[#fff] text-[24rpx] h-[40rpx] z-10" @click="signPopup = true">
|
||||||
|
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[28rpx] text-[#fff] mr-[6rpx]"></text>
|
||||||
|
<text class="text-[24rpx]">签到规则</text>
|
||||||
|
</view>
|
||||||
|
<view class="h-[382rpx]" :style="{ backgroundImage: 'url(' + img('static/resource/images/app/sigin_h5.png') + ')',backgroundSize: '100%', backgroundRepeat: 'no-repeat'}">
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<view class="sidebar-marign bg-[#fff] rounded-[16rpx] -mt-[85rpx]">
|
||||||
|
<view class="card-template">
|
||||||
|
<view class=" mb-[30rpx] flex justify-between items-center" v-if="flag">
|
||||||
|
<view class="flex items-center">
|
||||||
|
<text class="iconfont iconshangyibu text-[#333] text-[24rpx]" @click="changeMonth('prev')"></text>
|
||||||
|
<view class="mx-[30rpx] font-bold text-[32rpx] text-[#333] leading-[45rpx]">{{ state.curYear }}年{{ state.curMonth+1 }}月</view>
|
||||||
|
<text class="iconfont iconxiayibu1 text-[#333] text-[24rpx]" @click="changeMonth('next')"></text>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center">
|
||||||
|
<text class="nc-iconfont nc-icon-shangV6xx-1 text-[#626779] text-[26rpx]" @click="handleChange"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mb-[30rpx] flex justify-between items-center" v-else>
|
||||||
|
<view class="flex items-center">
|
||||||
|
<view class="font-500 text-[32rpx] text-[#333] leading-[45rpx]">已连续签到<text class="text-[#EF000C] mx-[4rpx]">{{ info.days }}</text>天</view>
|
||||||
|
</view>
|
||||||
|
<text class="nc-iconfont nc-icon-xiaV6xx text-[#626779] text-[26rpx]" v-if="!flag" @click="flag = !flag"></text>
|
||||||
|
</view>
|
||||||
|
<view class="relative z-9 bg-[#fff] rounded-[18rpx]">
|
||||||
|
<view>
|
||||||
|
<view class="flex items-center justify-between text-[#626779] text-[24rpx] mb-[16rpx]">
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周一</text>
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周二</text>
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周三</text>
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周四</text>
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周五</text>
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周六</text>
|
||||||
|
<text class="w-[14.28%] leading-[36rpx] text-center">周日</text>
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-wrap items-center justify-start" v-if="!flag">
|
||||||
|
<block v-for="(item,index) in state.weekCount" :key="index">
|
||||||
|
<view class="w-[14.28%] flex flex-col justify-center items-center">
|
||||||
|
<view v-if="filteredDate(item)" class="w-[74rpx] h-[92rpx] bg-[#F1F2F5] text-[#626779] box-border py-[10rpx] rounded-[8rpx] flex flex-col items-center" :class="{'sigin-bg !text-[#fff]': isVerDate(item),'!bg-[#F6FAFF] border-[1rpx] border-[#F0F4FA] border-solid': !isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1) ,'mb-[20rpx]':isCurrentDate(item),'mb-[30rpx]':!isCurrentDate(item)}" @click="getDayPackFn(item)">
|
||||||
|
<text class="text-[24rpx] leading-[28rpx] mb-[6rpx]">{{ filteredDate(item) }}</text>
|
||||||
|
<view v-if="filteredDate(item)" class="flex items-center justufy-center">
|
||||||
|
<image v-if="isPackDate(item)" :src="img('static/resource/images/app/package.png')" class="w-[40rpx] h-[40rpx]"></image>
|
||||||
|
<image v-else-if="isVerDate(item)" :src="img('static/resource/images/app/hassigin.png')" class="w-[34rpx] h-[34rpx]"></image>
|
||||||
|
<template v-else>
|
||||||
|
<image v-if="!isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1)" :src="img('static/resource/images/app/nosigin.png')" class="w-[34rpx] h-[34rpx]"></image>
|
||||||
|
<image v-else :src="img('static/resource/images/app/nosigin1.png')" class="w-[34rpx] h-[34rpx]"></image>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="w-[10rpx] h-[10rpx] rounded-[50%] bg-[#FF5527]" v-if="isCurrentDate(item)"></view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-wrap items-center justify-start" v-else>
|
||||||
|
<block v-for="(item,index) in state.dataCount" >
|
||||||
|
<view class="w-[14.28%] flex flex-col justify-center items-center mb-[30rpx]">
|
||||||
|
<view v-if="filteredDate(item)" class="w-[74rpx] h-[92rpx] bg-[#F6FAFF] text-[#626779] box-border py-[10rpx] rounded-[8rpx] flex flex-col items-center" :class="{'sigin-bg !text-[#fff]': isVerDate(item) && active ,'!bg-[#FDFDFD] border-[1rpx] border-[#F0F4FA] border-solid': !isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ,'mb-[20rpx]':isCurrentDate(item),'mb-[30rpx]':!isCurrentDate(item)}" @click="getDayPackFn(item)">
|
||||||
|
<text class="text-[24rpx] leading-[28rpx] mb-[6rpx]">{{ filteredDate(item) }}</text>
|
||||||
|
<view v-if="filteredDate(item)" class="flex items-center justufy-center">
|
||||||
|
<image v-if="isPackDate(item)" :src="img('static/resource/images/app/package.png')" class="w-[40rpx] h-[40rpx]"></image>
|
||||||
|
<image v-else-if="isVerDate(item) && active " :src="img('static/resource/images/app/hassigin.png')" class="w-[34rpx] h-[34rpx]"></image>
|
||||||
|
<template v-else>
|
||||||
|
<image v-if="!isVerDate(item) && item < state.curDate && (state.curMonth + 1) == (new Date().getMonth() + 1)" :src="img('static/resource/images/app/nosigin.png')" class="w-[34rpx] h-[34rpx]"></image>
|
||||||
|
<image v-else :src="img('static/resource/images/app/nosigin1.png')" class="w-[34rpx] h-[34rpx]"></image>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="w-[10rpx] h-[10rpx] rounded-[50%] bg-[#FF5527]" v-if="isCurrentDate(item)"></view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[40rpx] flex justify-center" v-if="state.curMonth + 1 == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ">
|
||||||
|
<button v-if="!info.is_sign" class="rounded-[40rpx] !bg-transparent" :style="{width:'490rpx',height:'88rpx',border:'none', color:'#fff', fontSize:'32rpx',lineHeight:'84rpx',backgroundImage: `url(${img('static/resource/images/app/button_bg2.png')})`,backgroundSize: '100%', backgroundRepeat: 'no-repeat'}" shape="circle" @click="setSignFn">
|
||||||
|
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[32rpx] text-[#fff] mr-[8rpx]"></text>
|
||||||
|
<text>立即签到</text>
|
||||||
|
</button>
|
||||||
|
<button v-else class="rounded-[40rpx] !bg-transparent" :style="{width:'490rpx',height:'88rpx',border:'none',color:'#fff', fontSize:'32rpx',lineHeight:'84rpx',backgroundImage: `url(${img('static/resource/images/app/button_bg1.png')})`,backgroundSize: '100%', backgroundRepeat: 'no-repeat'}" shape="circle">
|
||||||
|
<text class="nc-iconfont nc-icon-meiriqiandaoV6xx text-[32rpx] text-[#fff] mr-[8rpx]"></text>
|
||||||
|
<text>已签到</text>
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="mt-[20rpx] mb-[30rpx] sidebar-marign card-template" v-if="info && info.continue_award && Object.keys(info.continue_award).length">
|
||||||
|
<view class="mb-[30rpx] flex items-center">
|
||||||
|
<view class="font-500 text-[32rpx] text-[#333] leading-[44rpx]">签到奖励</view>
|
||||||
|
<!-- <view class="text-[#666] text-[26rpx] leading-[30rpx]">
|
||||||
|
<text>签到记录</text>
|
||||||
|
<image :src="img('static/resource/images/app/more.png')" class="w-[12rpx] h-[18rpx] ml-[8rpx]"></image>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
<view>
|
||||||
|
<view v-for="(item,index) in info.continue_award" :key="index" class="flex items-center border-box" :class="{'mt-[40rpx]':index}">
|
||||||
|
<view class="w-[90rpx] h-[90rpx] rounded-[50%] bg-[#E7F6FF] flex items-center justify-center flex-shrink-0" v-if="(index + 1) % 4 == 1">
|
||||||
|
<image :src="img('static/resource/images/app/icon_02.png')" class="w-[40rpx] h-[40rpx]"></image>
|
||||||
|
</view>
|
||||||
|
<view class="w-[90rpx] h-[90rpx] rounded-[50%] bg-[#ffefef] flex items-center justify-center flex-shrink-0" v-else-if="(index + 1) % 4 == 2">
|
||||||
|
<image :src="img('static/resource/images/app/icon_03.png')" class="w-[40rpx] h-[40rpx]"></image>
|
||||||
|
</view>
|
||||||
|
<view class="w-[90rpx] h-[90rpx] rounded-[50%] bg-[#d3feeb] flex items-center justify-center flex-shrink-0" v-else-if="(index + 1) % 4 == 3">
|
||||||
|
<image :src="img('static/resource/images/app/icon_04.png')" class="w-[40rpx] h-[40rpx]"></image>
|
||||||
|
</view>
|
||||||
|
<view class="w-[90rpx] h-[90rpx] rounded-[50%] bg-[#ffeddd] flex items-center justify-center flex-shrink-0" v-else-if="(index + 1) % 4 == 0">
|
||||||
|
<image :src="img('static/resource/images/app/icon_05.png')" class="w-[40rpx] h-[40rpx]"></image>
|
||||||
|
</view>
|
||||||
|
<view class="flex-1 mx-[20rpx]">
|
||||||
|
<view class="font-400 text-[28rpx] text-[#333] leading-[38rpx] mb-[8rpx]">连续签到{{item.continue_sign}}天</view>
|
||||||
|
<view class="flex flex-wrap" v-if="item.gift">
|
||||||
|
<view class="flex">
|
||||||
|
<image :src="img(item.gift.total.icon)" class="w-[30rpx] h-[30rpx] flex-shrink-0"></image>
|
||||||
|
<view class="text-[24rpx] ml-[8rpx] text-[#FF9000] leading-[34rpx] max-w-[330rpx]">{{item.gift.total.text}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex-shrink-0">
|
||||||
|
<view v-if="Number(info.days) < Number(item.continue_sign) " class="w-[130rpx] h-[56rpx] text-center bg-[#FFECE9] rounded-[28rpx] font-400 text-[26rpx] text-[#FF343E] leading-[56rpx]">待完成</view>
|
||||||
|
<view v-else class="w-[130rpx] h-[56rpx] text-center rounded-[28rpx] font-400 text-[26rpx] text-[#fff] leading-[56rpx]" style="background:linear-gradient( 90deg, #FB7939 0%, #FE120E 100%) ;">已完成</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="h-[100vh] w-[100vw] flex justify-center items-center" v-else>
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<top-tabbar :data="topTabbarData" :scrollBool="topTabarObj.getScrollBool()" class="top-header"/>
|
||||||
|
<!-- #endif -->
|
||||||
|
<u-empty text="签到未开启" width="347rpx" height="265rpx" :icon="img('static/resource/images/system/empty.png')"/>
|
||||||
|
</view>
|
||||||
|
<!-- 签到规则-->
|
||||||
|
<u-popup :show="signPopup" :round="16" mode="bottom" :closeable="true" @close="signPopup = false">
|
||||||
|
<view class="pt-[30rpx] px-[32rpx] pb-[20rpx]">
|
||||||
|
<view class="text-center text-[32rpx] font-700 text-[#323233]">签到规则</view>
|
||||||
|
<scroll-view :scroll-y="true" class="my-[20rpx] h-[360rpx] overflow-auto">
|
||||||
|
<block v-for="(item) in info.rule_explain.split('\n')">
|
||||||
|
<view class="text-[28rpx] leading-[40rpx] mb-[20rpx]">{{ item }}</view>
|
||||||
|
</block>
|
||||||
|
</scroll-view>
|
||||||
|
<view>
|
||||||
|
<button class="primary-btn-bg h-[66rpx] text-[#fff] text-[28rpx] border-[0] leading-[66rpx] rounded-[50rpx]" shape="circle" @click="signPopup = false">知道了</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
<!-- 签到奖励 -->
|
||||||
|
<u-popup :show="awardShow" class="award-popup" :customStyle="{backgroundColor:'transparent'}" @close="awardShow = false" mode="center" :round="5" :safeAreaInsetBottom="false" >
|
||||||
|
<view class="w-[550rpx] -mt-[124rpx]" v-if="Object.values(signAward).length">
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<image :src="img('static/resource/images/app/award.png')" class="w-[484rpx] h-[480rpx] z-10" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="-mt-[265rpx] bg-award rounded-[30rpx] pt-[100rpx] pb-[40rpx] mb-[50rpx] relative">
|
||||||
|
<view class="px-[32rpx]">
|
||||||
|
<view class="text-[48rpx] text-[#EF000C] font-bold leading-[68rpx] mb-[6rpx] text-center">{{ signAward.title }}</view>
|
||||||
|
<view class="text-[24rpx] text-[#F05F66] leading-[34rpx] text-center mb-[60rpx]" v-if="signAward.info">{{ signAward.info }}</view>
|
||||||
|
<view class="px-[68rpx] mb-[80rpx]">
|
||||||
|
<block v-for="(item,index) in signAward.awards">
|
||||||
|
<view class="flex items-center mb-[30rpx]" v-if="item.content">
|
||||||
|
<image :src="img(item.content.icon)" class="w-[42rpx] h-[42rpx]"></image>
|
||||||
|
<view class="ml-[20rpx] text-[28rpx] text-[#333] leading-[38rpx]">{{item.content.text }}</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-center relative z-30">
|
||||||
|
<view class="w-[370rpx] h-[88rpx] primary-btn-bg rounded-[50rpx] text-[#ffffff] text-center leading-[88rpx] text-[32rpx]" @click="awardShow = false">我知道了</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<text class="nc-iconfont nc-icon-cuohaoV6xx text-[#fff] text-[60rpx]" @click="awardShow = false"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
<!-- 查看当日或连续签到奖励 -->
|
||||||
|
<u-popup :show="packShow" class="award-popup" :customStyle="{backgroundColor:'transparent'}" @close="packShow = false" mode="center" :round="5" :safeAreaInsetBottom="false">
|
||||||
|
<view class="w-[550rpx] -mt-[124rpx]" v-if="Object.values(packInfo).length">
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<image :src="img('static/resource/images/app/award.png')" class="w-[484rpx] h-[480rpx] z-10" mode="aspectFill"></image>
|
||||||
|
</view>
|
||||||
|
<view class="-mt-[265rpx] bg-award rounded-[30rpx] pt-[100rpx] pb-[40rpx] mb-[50rpx] relative">
|
||||||
|
<view class="px-[32rpx]">
|
||||||
|
<view class="text-[48rpx] text-[#333] font-bold leading-[68rpx] mb-[6rpx] text-center relative z-20">
|
||||||
|
{{ packInfo.title }}
|
||||||
|
</view>
|
||||||
|
<view class="text-[24rpx] text-[#F05F66] leading-[34rpx] text-center mb-[60rpx]">{{ packInfo.info }}</view>
|
||||||
|
<view class="px-[68rpx] mb-[80rpx]">
|
||||||
|
<block v-for="(item,index) in packInfo.awards">
|
||||||
|
<template v-if="item.content">
|
||||||
|
<image :src="img(item.content.icon)" class="w-[42rpx] h-[42rpx]"></image>
|
||||||
|
<view class="ml-[20rpx] text-[28rpx] text-[#333] leading-[38rpx]">{{ item.content.text }}</view>
|
||||||
|
</template>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-center relative z-30">
|
||||||
|
<view class="w-[370rpx] h-[88rpx] border-[4rpx] border-[#EF000C] border-solid rounded-[50rpx] text-[#EF000C] text-center leading-[88rpx] text-[32rpx] font-500 box-border" @click="packShow = false">我知道了</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-center">
|
||||||
|
<text class="nc-iconfont nc-icon-cuohaoV6xx text-[#fff] text-[60rpx]" @click="packShow = false"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</view>
|
||||||
|
<u-loading-page bg-color="rgb(248,248,248)" :loading="loading" loadingText="" fontSize="16" color="#303133"></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref, toRefs, toRaw, computed } from 'vue'
|
||||||
|
import { redirect, img,pxToRpx } from '@/utils/common'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { getSignInfo,getSignConfig, setSign,getDayPack } from '@/app/api/member'
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import { topTabar } from '@/utils/topTabbar'
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
dataCount:[], //当月所有天数
|
||||||
|
weekCount:[], //如果签到周期是7天
|
||||||
|
curYear:0, // 当前年
|
||||||
|
curMonth:0, //当前月
|
||||||
|
curDate:0, //当前日
|
||||||
|
curWeek:0, //当前星期
|
||||||
|
signInList:[], // 签到列表
|
||||||
|
packList:[] //每个小周期内的礼包
|
||||||
|
})
|
||||||
|
const week = reactive({
|
||||||
|
weekDay:0, //当前天
|
||||||
|
week:0 //当前星期
|
||||||
|
})
|
||||||
|
const loading = ref(false)
|
||||||
|
const flag = ref(false)
|
||||||
|
const info = ref({}) //签到配置
|
||||||
|
const signPopup = ref(false)//签到规则弹框
|
||||||
|
const signAward = ref({}) //当日签到奖励
|
||||||
|
const awardShow = ref(false) // 每日签到弹框
|
||||||
|
const packShow = ref(false) //查看每天礼包
|
||||||
|
const packInfo = ref({}) //礼包奖励
|
||||||
|
const active = ref(false)
|
||||||
|
let currentYear: any = null
|
||||||
|
let currentMonth: any = null
|
||||||
|
onLoad(() =>{
|
||||||
|
let date=new Date()
|
||||||
|
state.curYear=date.getFullYear()
|
||||||
|
state.curMonth=date.getMonth()
|
||||||
|
state.curDate=date.getDate()
|
||||||
|
state.curWeek=date.getDay()
|
||||||
|
if(state.curWeek==0) state.curWeek = 7
|
||||||
|
|
||||||
|
currentYear=toRaw(state.curYear)
|
||||||
|
currentMonth=toRaw(state.curMonth)
|
||||||
|
|
||||||
|
//初始化执行
|
||||||
|
getDayCounts()
|
||||||
|
getWeekCounts()
|
||||||
|
getSignInfoFn({year:state.curYear,month:state.curMonth+1})
|
||||||
|
getSignConfigFn()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取签到配置
|
||||||
|
const getSignConfigFn = () =>{
|
||||||
|
loading.value = true
|
||||||
|
getSignConfig().then((res:any) =>{
|
||||||
|
info.value = res.data
|
||||||
|
if(!info.value.is_use){
|
||||||
|
topTabbarData = topTabarObj.setTopTabbarParam({title:'我的签到',topStatusBar:{textColor:'#333',bgColor:'#fff'}})
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每个周期签到日期
|
||||||
|
const getSignInfoFn = (data:any) =>{
|
||||||
|
getSignInfo(data).then((res:any) =>{
|
||||||
|
state.signInList = []
|
||||||
|
state.packList = []
|
||||||
|
state.packList = res.data.period
|
||||||
|
if(res.data.length){
|
||||||
|
state.signInList = res.data.days.map((el:any) =>{
|
||||||
|
return Number(el)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
active.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取当月总天数
|
||||||
|
const getDayCounts= () => {
|
||||||
|
let counts = new Date(state.curYear,state.curMonth+1,0).getDate()
|
||||||
|
//获取当前第一天是星期几
|
||||||
|
let firstWeekDay = new Date(state.curYear,state.curMonth,1).getDay()
|
||||||
|
state.dataCount = []
|
||||||
|
for(let i=1;i<counts+firstWeekDay;i++){
|
||||||
|
let val=i-firstWeekDay+ 1
|
||||||
|
state.dataCount.push(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 获取7天的日期签到
|
||||||
|
const getWeekCounts = () =>{
|
||||||
|
let now = `${state.curYear}-${state.curMonth+1 > 10 ? state.curMonth+1 : '0'+(state.curMonth+1)}-${state.curDate > 10 ? state.curDate : '0'+state.curDate }`
|
||||||
|
for (let i = state.curWeek - 1; i >= 0; i --) {
|
||||||
|
const day = new Date(now).getDate() - i
|
||||||
|
state.weekCount.push(day)
|
||||||
|
}
|
||||||
|
for (let i = 1; i <= 7 - state.curWeek; i++) {
|
||||||
|
const day = new Date(now).getDate() + i
|
||||||
|
state.weekCount.push(day)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//控制状态
|
||||||
|
const handleChange = () =>{
|
||||||
|
let nowDate = new Date().getMonth()
|
||||||
|
|
||||||
|
if(state.curMonth == nowDate){
|
||||||
|
flag.value = !flag.value
|
||||||
|
}else{
|
||||||
|
state.curMonth = new Date().getMonth()
|
||||||
|
state.curYear = new Date().getFullYear()
|
||||||
|
getSignInfoFn({year:state.curYear,month:state.curMonth+1})
|
||||||
|
flag.value = !flag.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//更改月份
|
||||||
|
const changeMonth=(type: string)=>{
|
||||||
|
state.dataCount=[]
|
||||||
|
if(type == 'prev'){
|
||||||
|
state.curMonth--
|
||||||
|
if(state.curMonth < 0){
|
||||||
|
state.curMonth = 11
|
||||||
|
state.curYear--
|
||||||
|
}
|
||||||
|
week.weekDay = 1
|
||||||
|
active.value = false
|
||||||
|
}else{
|
||||||
|
state.curMonth++
|
||||||
|
if(state.curMonth > 11){
|
||||||
|
state.curMonth = 0
|
||||||
|
state.curYear++
|
||||||
|
}
|
||||||
|
week.weekDay = 1
|
||||||
|
active.value = false
|
||||||
|
}
|
||||||
|
let data = {year:state.curYear,month:state.curMonth + 1}
|
||||||
|
getSignInfoFn(data)
|
||||||
|
getDayCounts()
|
||||||
|
}
|
||||||
|
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
|
||||||
|
// 点击签到
|
||||||
|
const setSignFn = () =>{
|
||||||
|
setSign().then(res =>{
|
||||||
|
if(Object.values(res.data).length){
|
||||||
|
signAward.value = res.data
|
||||||
|
// 如果没有奖励内容则不展示描述信息
|
||||||
|
let isShowInfo = 0
|
||||||
|
Object.values(signAward.value.awards).forEach((item,index)=>{
|
||||||
|
if(!item.content){
|
||||||
|
isShowInfo++;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(isShowInfo == Object.values(signAward.value.awards).length){
|
||||||
|
signAward.value.info = "";
|
||||||
|
}
|
||||||
|
getSignInfoFn({year:state.curYear,month:state.curMonth+1})
|
||||||
|
getSignConfigFn()
|
||||||
|
memberStore.getMemberInfo()
|
||||||
|
awardShow.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看每日礼包
|
||||||
|
const curPickDay = ref(null)
|
||||||
|
const getDayPackFn = (date:number) =>{
|
||||||
|
let {curYear,curMonth}=toRefs(state)
|
||||||
|
let itemDate=`${curYear.value}-${(curMonth.value+1) < 10 ? '0' + (curMonth.value+1) : (curMonth.value+1)}-${date < 10 ? '0'+date : date}`
|
||||||
|
let flag = state.packList.some(el =>{
|
||||||
|
return el.day == itemDate
|
||||||
|
})
|
||||||
|
if(!flag) return
|
||||||
|
curPickDay.value = date
|
||||||
|
let obj = {
|
||||||
|
year: state.curYear,
|
||||||
|
month:state.curMonth + 1,
|
||||||
|
day: date
|
||||||
|
}
|
||||||
|
getDayPack(obj).then((res:any) => {
|
||||||
|
if(JSON.stringify(res.data) != '[]'){
|
||||||
|
packInfo.value = res.data
|
||||||
|
packShow.value = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否签到
|
||||||
|
const isVerDate = (val:any) => {
|
||||||
|
return state.signInList.includes(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断是否是当前日期
|
||||||
|
const isCurrentDate=(date)=>{
|
||||||
|
if(date> 0 && date <= state.dataCount.length){
|
||||||
|
if(date == state.curDate && currentYear == state.curYear && currentMonth == state.curMonth){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPackDate = (date:any) =>{
|
||||||
|
let {curYear,curMonth}=toRefs(state)
|
||||||
|
let itemDate=`${curYear.value}-${(curMonth.value+1) < 10 ? '0' + (curMonth.value+1) : (curMonth.value+1)}-${date < 10 ? '0'+date : date}`
|
||||||
|
let flag = state.packList.some((el:any) =>{
|
||||||
|
return el.day == itemDate && el.award
|
||||||
|
})
|
||||||
|
return flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤日期
|
||||||
|
const filteredDate=(date :any)=>{
|
||||||
|
return date > 0 ? date : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取系统状态栏的高度
|
||||||
|
let menuButtonInfo = {};
|
||||||
|
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
|
||||||
|
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
|
||||||
|
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
|
||||||
|
// #endif
|
||||||
|
/********* 自定义头部 - start ***********/
|
||||||
|
const topTabarObj = topTabar()
|
||||||
|
let topTabbarData = topTabarObj.setTopTabbarParam({title:'我的签到'})
|
||||||
|
/********* 自定义头部 - end ***********/
|
||||||
|
|
||||||
|
const headStyle = computed(() => {
|
||||||
|
let style = pxToRpx(Number(menuButtonInfo.height) + menuButtonInfo.top + 8)+ 382 + 'rpx;'
|
||||||
|
return style
|
||||||
|
})
|
||||||
|
const topStyle = computed(() => {
|
||||||
|
let style = pxToRpx(Number(menuButtonInfo.height) + menuButtonInfo.top + 8)+38 + 'rpx;'
|
||||||
|
return style
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bg-color{
|
||||||
|
background-color: rgba(102,102,102,0.4);
|
||||||
|
}
|
||||||
|
.sigin-bg{
|
||||||
|
background: linear-gradient( 90deg, #FFA359 0%, #FF5426 100%), #F2F2F2;
|
||||||
|
}
|
||||||
|
:deep(.award-popup .u-popup__content){
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.bg-award{
|
||||||
|
background: linear-gradient( 51deg, #FFFBFC 0%, #FFFCF9 59%, #FFE7E7 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-button{
|
||||||
|
background: linear-gradient( 180deg, #FFEAE1 0%, #FFCDD0 34%, #E0052C 100%);
|
||||||
|
border-radius: 40rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
20
uni-app/src/app/pages/pay/browser.vue
Normal file
20
uni-app/src/app/pages/pay/browser.vue
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-screen h-screen bg-[#424040] text-right" :style="themeColor()">
|
||||||
|
<image :src="img('static/resource/images/pay/invite_friends_share.png')" mode="heightFix" class="pt-[30rpx] pr-[30rpx] h-[200rpx]"/>
|
||||||
|
<view class="text-white font-bold pt-[30rpx] pr-[30rpx]">点击右上角跳转到浏览器打开</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { img, isWeixinBrowser } from '@/utils/common'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
|
||||||
|
onLoad((data : any) => {
|
||||||
|
if (!isWeixinBrowser() && data.alipay) {
|
||||||
|
uni.setStorageSync('paymenting', { trade_type: data.trade_type, trade_id: data.trade_id })
|
||||||
|
location.href = data.alipay
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
74
uni-app/src/app/pages/pay/result.vue
Normal file
74
uni-app/src/app/pages/pay/result.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<view class="w-screen h-screen flex flex-col items-center" v-if="payInfo">
|
||||||
|
<view class="flex-1 flex flex-col items-center w-full pt-[100rpx]">
|
||||||
|
<text class="iconfont text-2xl" :class="payInfo.status==2 ? 'text-primary iconduigou' : 'iconzhifushibai text-red'"></text>
|
||||||
|
<view class=" text-sm">{{ payInfo.status == 2 ? t('pay.paySuccess') : t('pay.payFail') }}</view>
|
||||||
|
<view class="text-xl font-bold pt-[30rpx]">
|
||||||
|
<text class="text-base">{{ t('currency') }}</text>
|
||||||
|
<text>{{ moneyFormat(payInfo.money) }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="pb-[200rpx] w-[240rpx]">
|
||||||
|
<u-button type="primary" :text="payInfo.status == 2 ? t('complete') : t('close')" :plain="true" @click="complete"></u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<u-modal :show="loading" :showCancelButton="true" :confirmText="t('pay.completePay')" :cancelText="t('pay.incompletePay')" @cancel="complete" confirmColor="var(--primary-color)">
|
||||||
|
<view class="py-[20rpx]">
|
||||||
|
<u-loading-icon :text="t('pay.getting')" textSize="16" mode="circle" :vertical="true"></u-loading-icon>
|
||||||
|
</view>
|
||||||
|
</u-modal>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { getPayInfo as getPayInfoApi } from '@/app/api/pay'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import { redirect, moneyFormat } from '@/utils/common'
|
||||||
|
import { getFirstPage } from '@/utils/pages'
|
||||||
|
|
||||||
|
const payInfo = ref<AnyObject | null>(null)
|
||||||
|
const loading = ref(false)
|
||||||
|
let tradeType = ''
|
||||||
|
let tradeId = 0
|
||||||
|
let requestNum = 0
|
||||||
|
|
||||||
|
onLoad((data : any) => {
|
||||||
|
tradeType = data.trade_type
|
||||||
|
tradeId = data.trade_id
|
||||||
|
getPayInfo()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取支付信息
|
||||||
|
*/
|
||||||
|
const getPayInfo = () => {
|
||||||
|
getPayInfoApi(tradeType, tradeId).then((res: responseResult) => {
|
||||||
|
if (!uni.$u.test.isEmpty(res.data)) {
|
||||||
|
if (res.data.status == 1 && requestNum < 5) {
|
||||||
|
loading.value = true
|
||||||
|
requestNum++
|
||||||
|
setTimeout(() => {
|
||||||
|
getPayInfo()
|
||||||
|
}, 1000)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payInfo.value = res.data
|
||||||
|
loading.value = false
|
||||||
|
uni.setNavigationBarTitle({
|
||||||
|
title: payInfo.value.status == 2 ? t('pay.paySuccess') : t('pay.payFail')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const complete = () => {
|
||||||
|
const payReturn = decodeURIComponent(uni.getStorageSync('payReturn'))
|
||||||
|
if (payReturn) redirect({ url: payReturn, mode: 'reLaunch' })
|
||||||
|
else redirect({ url: getFirstPage(), param: { code: payInfo.value?.out_trade_no }, mode: 'reLaunch' })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
86
uni-app/src/app/pages/setting/index.vue
Normal file
86
uni-app/src/app/pages/setting/index.vue
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<view class="w-full h-screen box-border pt-[30rpx] bg-page setting-wrap" :style="themeColor()">
|
||||||
|
<view class="m-[30rpx] mt-0 bg-white rounded-md overflow-hidden px-[20rpx] py-[10rpx]">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<u-cell :title="t('personalSettings')" :is-link="true" url="/app/pages/member/personal"></u-cell>
|
||||||
|
<u-cell :title="t('switchLang')" :is-link="true" :value="lang" @click="langSheetShow = true"></u-cell>
|
||||||
|
<u-cell :title="t('version')" :value="version"></u-cell>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
<view class="m-[30rpx] bg-white rounded-md overflow-hidden px-[20rpx] py-[10rpx]">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<u-cell :title="t('userAgreement')" :is-link="true" url="/app/pages/auth/agreement?key=service"></u-cell>
|
||||||
|
<u-cell :title="t('privacyAgreement')" :is-link="true" url="/app/pages/auth/agreement?key=privacy"></u-cell>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="m-[30rpx] bg-white rounded-md overflow-hidden px-[20rpx]">
|
||||||
|
<u-cell-group :border="false">
|
||||||
|
<view class="text-center py-[20rpx] text-sm" @click="memberStore.logout(true)">{{ t('logout') }}</view>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<u-action-sheet :actions="langList" :show="langSheetShow" :closeOnClickOverlay="true"
|
||||||
|
:safeAreaInsetBottom="true"
|
||||||
|
@close="langSheetShow = false" @select="switchLang"></u-action-sheet>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed } from 'vue'
|
||||||
|
import useMemberStore from '@/stores/member'
|
||||||
|
import { t, language } from '@/locale'
|
||||||
|
import { currRoute, isWeixinBrowser } from '@/utils/common'
|
||||||
|
|
||||||
|
const memberStore = useMemberStore()
|
||||||
|
|
||||||
|
const version = ref(import.meta.env.VITE_APP_VERSION)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支持的语言列表
|
||||||
|
*/
|
||||||
|
const langList = reactive({
|
||||||
|
'zh-Hans': { name: '简体中文', fontSize: '14', value: 'zh-Hans' },
|
||||||
|
'en': { name: 'English', fontSize: '14', value: 'en' }
|
||||||
|
})
|
||||||
|
const langSheetShow = ref(false)
|
||||||
|
|
||||||
|
// 当前语言
|
||||||
|
const lang = computed(() => {
|
||||||
|
const lang = uni.getLocale()
|
||||||
|
return langList[lang].name
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换语言
|
||||||
|
*/
|
||||||
|
const switchLang = (lang) => {
|
||||||
|
language.loadAllLocaleMessages('app', lang.value)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
background: var(--page-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.u-cell-group__wrapper) {
|
||||||
|
.u-cell__body {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
.u-cell__value{
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.u-cell {
|
||||||
|
&:last-child .u-line {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.setting-wrap .u-cell--clickable{
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
81
uni-app/src/app/pages/verify/detail.vue
Normal file
81
uni-app/src/app/pages/verify/detail.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()" class="bg-[#f8f8f8] min-h-[100vh] overflow-hidden">
|
||||||
|
<block v-if="!loading">
|
||||||
|
<view class="pt-[20rpx] sidebar-marign">
|
||||||
|
<view class="flex flex-col card-template">
|
||||||
|
<view class="flex" :class="{'mb-[20rpx]': verifyInfo.value.list.length-1 != index}" v-for="(item,index) in verifyInfo.value.list" :key="index">
|
||||||
|
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-if="item.cover" :src="img(item.cover)"></image>
|
||||||
|
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
|
||||||
|
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
|
||||||
|
<view class="leading-[1.3] text-[28rpx] multi-hidden">{{item.name}}</view>
|
||||||
|
<view class="self-end text-[#626779] text-[26rpx] mt-[20rpx]">x1</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="flex flex-col card-template mt-[20rpx]">
|
||||||
|
<view class="text-[32rpx] text-[#333333] font-500 leading-[1.2] mb-[30rpx]">核销信息</view>
|
||||||
|
<view class="flex justify-between h-[36rpx] items-center">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">核销类型</text>
|
||||||
|
<view class="text-[26rpx] text-[#333]">{{verifyInfo.type_name}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-between h-[36rpx] items-center mt-[20rpx]">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">核销状态</text>
|
||||||
|
<view class="text-[26rpx] text-[#333]">已核销</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-between h-[36rpx] items-center mt-[20rpx]">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">核销时间</text>
|
||||||
|
<view class="text-[#333333] text-[26rpx]">{{verifyInfo.create_time}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex justify-between h-[36rpx] items-center mt-[20rpx]">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">核销人员</text>
|
||||||
|
<view class="text-[#333333] text-[26rpx]">{{verifyInfo.member ? verifyInfo.member.nickname : '--'}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex items-center h-[36rpx] justify-between mt-[20rpx]" v-for="(item,index) in verifyInfo.value.content.fixed">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">{{item.title}}</text>
|
||||||
|
<view class="text-[26rpx] text-[#333]">{{item.value}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-for="(item,index) in verifyInfo.value.content.diy" :key="index" class="card-template mt-[20rpx]">
|
||||||
|
<view class="text-[32rpx] text-[#333333] font-500 leading-[1.2] mb-[30rpx]">{{item.title}}</view>
|
||||||
|
<view class="flex items-center h-[36rpx] justify-between mt-[20rpx]" v-for="(subItem,subIndex) in item.list" :key="subIndex" :class="{'mt-30rpx' : subIndex == '0'}">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">{{subItem.title}}</text>
|
||||||
|
<view class="text-[26rpx] text-[#333]">{{subItem.value}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</block>
|
||||||
|
<u-loading-page :loading="loading" loading-text="" loadingColor="var(--primary-color)" iconSize="35"></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { onLoad,onShow } from '@dcloudio/uni-app'
|
||||||
|
import { img,redirect, getToken } from '@/utils/common';
|
||||||
|
import { getVerifyDetail } from '@/app/api/verify'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const code = ref('');
|
||||||
|
onLoad((option:any)=> {
|
||||||
|
if (option.code) code.value = option.code;
|
||||||
|
})
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
if(getToken()){
|
||||||
|
getVerifyDetailFn();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const verifyInfo = ref({})
|
||||||
|
const getVerifyDetailFn = ()=>{
|
||||||
|
loading.value = true;
|
||||||
|
getVerifyDetail(code.value).then((res:any) =>{
|
||||||
|
verifyInfo.value = res.data;
|
||||||
|
loading.value = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
216
uni-app/src/app/pages/verify/index.vue
Normal file
216
uni-app/src/app/pages/verify/index.vue
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<view class="w-[100vw] min-h-[100vh] bg-[#f8f8f8]" v-if="!loading">
|
||||||
|
<view class="w-full bg-[#fff] verify-box h-[760rpx]">
|
||||||
|
<view class="text-[var(--primary-color)] fixed top-[40rpx] right-[30rpx] flex items-center" @click="redirect({url:'/app/pages/verify/record'})">
|
||||||
|
<image class="w-[26rpx] h-[28rpx]" :src="img('static/resource/images/verify/history.png')"/>
|
||||||
|
<text class="text-[26rpx] ml-[10rpx]">核销记录</text>
|
||||||
|
</view>
|
||||||
|
<view v-show="operationType == 'sweepCode'" class="flex flex-col items-center justify-center">
|
||||||
|
<view class="sweep-code flex items-center justify-center" @click="scanCode">
|
||||||
|
<image class="w-[354rpx] h-[354rpx]" :src="img('static/resource/images/verify/saoma.png')"/>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[40rpx] text-[32rpx]">点击扫描二维码</view>
|
||||||
|
<view class="mt-[20rpx] text-[#8288A2] text-[26rpx] font-400 pb-[142rpx]">扫描二维码进行核销</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-show="operationType == 'manualInput'">
|
||||||
|
<view class="flex pt-[126rpx] items-center justify-center">
|
||||||
|
<view class="flex justify-center items-center flex-col pr-[30rpx] w-[130rpx]">
|
||||||
|
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/shuruhexiaoma.png')"/>
|
||||||
|
<view class="text-[26rpx] h-[36rpx] leading-[36rpx] mt-[12rpx]">验证核销码</view>
|
||||||
|
</view>
|
||||||
|
<image class="w-[74rpx] h-[12rpx] mb-[50rpx]" :src="img('static/resource/images/verify/youjiantou.png')"/>
|
||||||
|
<view class="flex justify-center items-center flex-col pl-[30rpx] w-[130rpx]">
|
||||||
|
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/hexiao1.png')"/>
|
||||||
|
<view class="text-[26rpx] h-[36rpx] leading-[36rpx] mt-[12rpx]">核销</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="mt-[50rpx]">
|
||||||
|
<view class="h-[90rpx] border-[2rpx] border-solid border-[#DCE0EF] rounded-[16rpx] box-border p-[20rpx] mx-[60rpx] flex items-center" >
|
||||||
|
<text class="nc-iconfont nc-icon-saotiaoxingmaV6xx text-[44rpx] text-[#EF000C]"></text>
|
||||||
|
<input type="text" placeholder="请输入核销码" class="h-[90rpx] border-none text-start ml-[30rpx] text-[28rpx] flex-1" placeholder-class="_placeholder" v-model="verify_code" :focus="isFocus" ref="input"/>
|
||||||
|
</view>
|
||||||
|
<view class="h-[88rpx] min-w-[630rpx] text-[#fff] flex items-center justify-center !text-[32rpx] save-btn rounded-[50rpx] h-[88rpx] mx-[60rpx] mt-[146rpx] relative z-1" @click="confirm">确认</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="w-[630rpx] h-[100rpx] bg-[#fff] mx-[auto] mt-[220rpx] rounded-[90rpx] flex relative action-type-wrap">
|
||||||
|
<view class="relative w-[51%] pr-[50rpx] box-border rounded-[50rpx] z-0 flex flex-col items-center justify-center" @click="changeOperationType('sweepCode')" :class="{'xuanZhong1': operationType == 'sweepCode'}">
|
||||||
|
<text class="nc-iconfont nc-icon-saoyisaoV6xx !text-[40rpx]"></text>
|
||||||
|
<view class="text-[24rpx] leading-[1] mt-[10rpx]">扫码核销</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-col items-center flex-col w-[120rpx] h-[120rpx] bg-[#FF7354] rounded-[50%] absolute top-[-10rpx] left-[255rpx] heXiao text-white z-10 shrink-0">
|
||||||
|
<view class="nc-iconfont nc-icon-saotiaoxingmaV6xx ns-gradient-otherpages-member-balance-balance-rechange !text-[44rpx] mt-[19rpx]"></view>
|
||||||
|
<view class="text-[24rpx] mt-[8rpx] leading-[34rpx] h-[34rpx]">核销台</view>
|
||||||
|
</view>
|
||||||
|
<view class="relative w-[51%] pl-[50rpx] box-border rounded-[50rpx] z-0 flex flex-col items-center justify-center" :class="{'xuanZhong': operationType == 'manualInput'}" @click="changeOperationType('manualInput')">
|
||||||
|
<text class="iconfont iconVector-77 !text-[40rpx]"></text>
|
||||||
|
<view class="ml-[20rpx] text-[24rpx] leading-[1] mt-[10rpx]" @click="focus">手动输入</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<!-- 小程序隐私协议 -->
|
||||||
|
<privacy-popup ref="privacyPopup"></privacy-popup>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
<u-loading-page :loading="loading" loading-text="" loadingColor="var(--primary-color)" iconSize="35"></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { img,redirect, isWeixinBrowser, getToken } from '@/utils/common';
|
||||||
|
import {onShow} from '@dcloudio/uni-app'
|
||||||
|
import { getVerifierInfo, getCheckVerifier } from '@/app/api/verify'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
import wechat from '@/utils/wechat'
|
||||||
|
|
||||||
|
const operationType = ref('manualInput'); //类型
|
||||||
|
// #ifdef H5
|
||||||
|
operationType.value = 'manualInput';
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
operationType.value = 'sweepCode';
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
const isFocus = ref(false)
|
||||||
|
const verify_code = ref('');
|
||||||
|
const loading = ref(true)
|
||||||
|
onShow(() => {
|
||||||
|
if(getToken()) checkIsVerifier();
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检测是否是核销员
|
||||||
|
const checkIsVerifier = () => {
|
||||||
|
getCheckVerifier().then((res:any) =>{
|
||||||
|
if(!res.data){
|
||||||
|
uni.showToast({
|
||||||
|
title: '非核销员无此权限',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if(getCurrentPages().length > 1){
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
redirect({
|
||||||
|
url: '/app/pages/member/index',
|
||||||
|
mode: 'reLaunch'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}else{
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const scanCode = () => {
|
||||||
|
// #ifdef MP
|
||||||
|
uni.scanCode({
|
||||||
|
onlyFromCamera: true,
|
||||||
|
success: res => {
|
||||||
|
if (res.errMsg == 'scanCode:ok') {
|
||||||
|
let code = res.result;
|
||||||
|
redirect({ url: '/app/pages/verify/verify', param: { code} })
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.errorMsg,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
if (isWeixinBrowser()) {
|
||||||
|
wechat.init();
|
||||||
|
wechat.scanQRCode(res => {
|
||||||
|
if (res.resultStr) {
|
||||||
|
let code = res.resultStr;
|
||||||
|
redirect({ url: '/app/pages/verify/verify', param: { code} })
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
let isLoading = false;
|
||||||
|
const confirm = () => {
|
||||||
|
var reg = /[\S]+/;
|
||||||
|
if (!reg.test(verify_code.value)) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请输入核销码',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isLoading) return false;
|
||||||
|
isLoading = true;
|
||||||
|
|
||||||
|
getVerifierInfo(verify_code.value).then((res:any) =>{
|
||||||
|
isLoading = false;
|
||||||
|
redirect({ url: '/app/pages/verify/verify', param: { code: verify_code.value} })
|
||||||
|
}).catch(() => {
|
||||||
|
isLoading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const focus = () => {
|
||||||
|
isFocus.value = !isFocus.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeOperationType = (type: string) => {
|
||||||
|
// #ifdef H5
|
||||||
|
if (type == 'sweepCode' && !isWeixinBrowser()) {
|
||||||
|
uni.showToast({
|
||||||
|
title: 'H5端不支持扫码核销',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
operationType.value = type;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.action-type-wrap {
|
||||||
|
box-shadow: 0 6px 6px 0 rgba(0, 0, 0, 0.03), 0 4px 2px 0 rgba(0, 0, 0, 0.04);;
|
||||||
|
}
|
||||||
|
.heXiao{
|
||||||
|
background: linear-gradient( 180deg, #FF7354 0%, #FF020F 100%), #EF000C;
|
||||||
|
}
|
||||||
|
.xuanZhong{
|
||||||
|
background: linear-gradient( 270deg, #FFD1D1 0%, rgba(255,209,209,0.2) 100%), #FFFFFF;
|
||||||
|
color:#EF000C;
|
||||||
|
}
|
||||||
|
.xuanZhong1{
|
||||||
|
background: linear-gradient( 90deg, #FFD1D1 0%, rgba(255,209,209,0.2) 100%), #FFFFFF;
|
||||||
|
color:#EF000C;
|
||||||
|
}
|
||||||
|
.sweep-code {
|
||||||
|
width: 354rpx;
|
||||||
|
height: 354rpx;
|
||||||
|
box-shadow: 0 8px 8px 0 rgba(0, 0, 0, 0.03), 0 6px 3px 0 rgba(0, 0, 0, 0.02);
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-top: 146rpx;
|
||||||
|
}
|
||||||
|
.verify-box {
|
||||||
|
border-bottom-left-radius: 400rpx 60rpx;
|
||||||
|
border-bottom-right-radius: 400rpx 60rpx;
|
||||||
|
}
|
||||||
|
.save-btn{
|
||||||
|
background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;
|
||||||
|
}
|
||||||
|
._placeholder{
|
||||||
|
color: #8288A2;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
129
uni-app/src/app/pages/verify/record.vue
Normal file
129
uni-app/src/app/pages/verify/record.vue
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
<template>
|
||||||
|
<view class="bg-[#f8f8f8] min-h-screen overflow-hidden" :style="themeColor()">
|
||||||
|
<view class="fixed left-0 right-0 top-0 z-99 bg-[#fff] px-[var(--sidebar-m)]">
|
||||||
|
<view class="py-[14rpx] flex items-center justify-between">
|
||||||
|
<view class="flex-1 flex items-center h-[60rpx] bg-[#F8F9FD] rounded-[30rpx] px-[20rpx] mr-[30rpx]">
|
||||||
|
<u-input class="flex-1" maxlength="50" v-model="keyword" @confirm="searchTypeFn()" placeholder="请输入搜索关键词" placeholderClass="text-[#8288A2] text-[24rpx]" fontSize="26rpx" clearable border="none"></u-input>
|
||||||
|
<text class="nc-iconfont nc-icon-sousuo-duanV6xx1 text-[32rpx] ml-[18rpx] !text-[#999]" @click="searchTypeFn()"></text>
|
||||||
|
</view>
|
||||||
|
<view class="nc-iconfont nc-icon-riliV6xx !text-[30rpx] leading-[36rpx]" @click="handleSelect"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<mescroll-body ref="mescrollRef" top="108rpx" @init="mescrollInit" :down="{ use: false }" @up="geVerifyRecordFn">
|
||||||
|
<view class="sidebar-marign">
|
||||||
|
<block v-for="(item,index) in list" :key="item.id">
|
||||||
|
<view class="w-full flex flex-col mb-[20rpx] card-template" @click="toLink(item)">
|
||||||
|
<view class="flex items-center mb-[30rpx] leading-[1]">
|
||||||
|
<view class="nc-iconfont nc-icon-hexiaotaiV6xx !text-[26rpx] pr-[10rpx]"></view>
|
||||||
|
<text class="truncate text-[#333333] text-[26rpx]">核销码:{{ item.code }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="flex flex-1" v-for="(dataItem,dataIndex) in item.value.list" :key="dataIndex">
|
||||||
|
<u--image class="rounded-[8rpx] overflow-hidden" width="120rpx" height="120rpx" :src="img(dataItem.cover ? dataItem.cover : '')" model="aspectFill">
|
||||||
|
<template #error>
|
||||||
|
<image class="w-[120rpx] h-[120rpx] rounded-[8rpx] overflow-hidden" :src="img('static/resource/images/diy/shop_default.jpg')" mode="aspectFill"></image>
|
||||||
|
</template>
|
||||||
|
</u--image>
|
||||||
|
<view class="flex flex-col flex-1 justify-between ml-[20rpx] py-[4rpx]" >
|
||||||
|
<view class="leading-[1.3] multi-hidden text-[28rpx] text-[#333]">{{dataItem.name}}</view>
|
||||||
|
<view class="self-end text-[26rpx] mt-[10rpx] text-[#626779]">x1</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex bg-[#F8F9FD] py-[20rpx] px-[20rpx] rounded-[12rpx] mt-[20rpx]">
|
||||||
|
<view class="flex-1">
|
||||||
|
<view class="text-[22rpx] text-[#8288A2] mb-[10rpx] leading-[30rpx]">核销时间</view>
|
||||||
|
<view class="text-[26rpx] text-[#333] leading-[36rpx]">{{ item.create_time }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex-1">
|
||||||
|
<view class="text-[22rpx] text-[#8288A2] mb-[10rpx] leading-[30rpx]">核销员</view>
|
||||||
|
<view class="text-[26rpx] text-[#333] leading-[36rpx]">{{ item.member ? item.member.nickname : '--' }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
<view class="mx-[30rpx] rounded-[16rpx] noData flex items-center justify-center" v-if="!list.length && loading">
|
||||||
|
<mescroll-empty :option="{tip : '暂无核销记录'}"></mescroll-empty>
|
||||||
|
</view>
|
||||||
|
</mescroll-body>
|
||||||
|
<!-- 时间选择 -->
|
||||||
|
<select-date ref="selectDateRef" @confirm="confirmFn" />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, reactive, computed } from 'vue'
|
||||||
|
import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue'
|
||||||
|
import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue'
|
||||||
|
import useMescroll from '@/components/mescroll/hooks/useMescroll.js'
|
||||||
|
import { onPageScroll, onReachBottom } from '@dcloudio/uni-app'
|
||||||
|
import { getVerifyRecords } from '@/app/api/verify'
|
||||||
|
import { img, redirect } from '@/utils/common'
|
||||||
|
import selectDate from '@/components/select-date/select-date.vue';
|
||||||
|
|
||||||
|
const keyword = ref<string>('')
|
||||||
|
const create_time = ref([])
|
||||||
|
const list = ref<Array<Object>>([])
|
||||||
|
const loading = ref<boolean>(false)
|
||||||
|
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||||
|
|
||||||
|
const geVerifyRecordFn = (mescroll) => {
|
||||||
|
loading.value = false;
|
||||||
|
let data : object = {
|
||||||
|
page: mescroll.num,
|
||||||
|
limit: mescroll.size,
|
||||||
|
keyword:keyword.value,
|
||||||
|
create_time: create_time.value
|
||||||
|
};
|
||||||
|
|
||||||
|
getVerifyRecords(data).then((res) => {
|
||||||
|
let newArr = (res.data.data as Array<Object>);
|
||||||
|
//设置列表数据
|
||||||
|
if (mescroll.num == 1) {
|
||||||
|
list.value = []; //如果是第一页需手动制空列表
|
||||||
|
}
|
||||||
|
list.value = list.value.concat(newArr);
|
||||||
|
mescroll.endSuccess(newArr.length);
|
||||||
|
loading.value = true;
|
||||||
|
}).catch(() => {
|
||||||
|
loading.value = true;
|
||||||
|
mescroll.endErr(); // 请求失败, 结束加载
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const toLink = (data: AnyObject)=> {
|
||||||
|
redirect({ url: '/app/pages/verify/detail', param: { code: data.code } })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关键词搜索条件搜索
|
||||||
|
const searchTypeFn = () =>{
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
//日期筛选
|
||||||
|
const selectDateRef = ref()
|
||||||
|
const handleSelect = () =>{
|
||||||
|
selectDateRef.value.show = true
|
||||||
|
}
|
||||||
|
// 确定时间筛选
|
||||||
|
const confirmFn = (data) =>{
|
||||||
|
create_time.value = data;
|
||||||
|
list.value = []
|
||||||
|
getMescroll().resetUpScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.uni-picker-view-content){
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
:deep(.uni-picker-view-indicator::before){
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
:deep(.uni-picker-view-indicator::after){
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.noData{
|
||||||
|
height: calc(100vh - 132rpx - constant(safe-area-inset-bottom));
|
||||||
|
height: calc(100vh - 132rpx - env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
150
uni-app/src/app/pages/verify/verify.vue
Normal file
150
uni-app/src/app/pages/verify/verify.vue
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()" class="bg-[#f8f8f8] min-h-[100vh] overflow-hidden">
|
||||||
|
<block v-if="!loading && verifyInfo && verifyInfo.value">
|
||||||
|
<view class="w-full bg-[#fff] flex justify-center">
|
||||||
|
<view class="text-[var(--primary-color)] absolute top-[40rpx] right-[30rpx] flex items-center" @click="redirect({url:'/app/pages/verify/record'})">
|
||||||
|
<image class="w-[26rpx] h-[28rpx]" :src="img('static/resource/images/verify/history.png')"/>
|
||||||
|
<text class="text-[26rpx] ml-[10rpx]">核销记录</text>
|
||||||
|
</view>
|
||||||
|
<view class="flex pt-[120rpx] pb-[30rpx] items-center">
|
||||||
|
<view class="flex justify-center items-center flex-col pr-[30rpx] w-[130rpx]">
|
||||||
|
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/yanzhenghexiaoma.png')"/>
|
||||||
|
<view class="text-[26rpx] mt-[12rpx] h-[36rpx] leading-[36rpx]">验证核销码</view>
|
||||||
|
</view>
|
||||||
|
<image class="w-[74rpx] h-[12rpx] mb-[50rpx]" :src="img('static/resource/images/verify/youjiantou.png')"/>
|
||||||
|
<view class="flex justify-center items-center flex-col pl-[30rpx] w-[130rpx]">
|
||||||
|
<image class="w-[100rpx] h-[100rpx]" :src="img('static/resource/images/verify/hexiao.png')"/>
|
||||||
|
<view class="text-[26rpx] mt-[12rpx] h-[36rpx] leading-[36rpx]">确定核销</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="card-template mt-[20rpx] sidebar-marign">
|
||||||
|
<view class="flex" :class="{'mb-[20rpx]': (verifyInfo.value.list.length - 1 != index)}" v-for="(item,index) in verifyInfo.value.list" :key="index">
|
||||||
|
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-if="item.cover" :src="img(item.cover)"></image>
|
||||||
|
<image class="w-[150rpx] h-[150rpx] rounded-[8rpx]" mode="aspectFill" v-else :src="img('addon/tourism/tourism/member/hotel.png')"></image>
|
||||||
|
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
|
||||||
|
<view class="leading-[1.3] multi-hidden">{{item.name}}</view>
|
||||||
|
<view class="self-end text-[#626779] text-[28rpx] mt-[10rpx]">x1</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="card-template mt-[20rpx] sidebar-marign">
|
||||||
|
<view class="text-[32rpx] font-500 leading-[1.3]">核销信息</view>
|
||||||
|
<view class="flex pt-[30rpx] items-center justify-between min-h-[36rpx]">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">核销类型</text>
|
||||||
|
<view class="text-[26rpx] text-[#333333]">{{verifyInfo.type_name}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="flex pt-[20rpx] items-center justify-between min-h-[36rpx]" v-for="(item,index) in verifyInfo.value.content.fixed">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">{{item.title}}</text>
|
||||||
|
<view class="text-[26rpx] text-[#333333]">{{item.value}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-for="(item,index) in verifyInfo.value.content.diy" :key="index" class="card-template mt-[20rpx] sidebar-marign">
|
||||||
|
<view class="text-[32rpx] font-500 leading-[1.3]">{{item.title}}</view>
|
||||||
|
<view class="flex items-center justify-between min-h-[36rpx]" :class="{'pt-[30rpx]': subIndex==0, 'pt-[20rpx]': subIndex!=0}" v-for="(subItem,subIndex) in item.list" :key="subIndex">
|
||||||
|
<text class="text-[26rpx] text-[#626779]">{{subItem.title}}</text>
|
||||||
|
<text class="text-[26rpx] text-[#333333]">{{ subItem.value }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<text class=" min-w-[630rpx] fixed bottom-[60rpx] confirmBtn text-[#fff] flex items-center justify-center !text-[32rpx] rounded-[50rpx] h-[88rpx] ml-[60rpx] mr-[60rpx]" @click="verifyFn">确定</text>
|
||||||
|
</block>
|
||||||
|
<u-loading-page :loading="loading" loading-text="" loadingColor="var(--primary-color)" iconSize="35"></u-loading-page>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { onLoad ,onShow} from '@dcloudio/uni-app'
|
||||||
|
import { img,redirect, getToken } from '@/utils/common';
|
||||||
|
import { getVerifierInfo, getCheckVerifier, verify } from '@/app/api/verify'
|
||||||
|
import { t } from '@/locale'
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
const code = ref('');
|
||||||
|
onLoad((option:any)=> {
|
||||||
|
if (option.code) code.value = option.code;
|
||||||
|
// 小程序扫码进入
|
||||||
|
if (option.scene) {
|
||||||
|
let sceneParams: any = decodeURIComponent(option.scene).split('&');
|
||||||
|
if (sceneParams.length) {
|
||||||
|
sceneParams.forEach((item: any) => {
|
||||||
|
if (item.indexOf('code') != -1) code.value = item.split('-')[1];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
if(getToken()){
|
||||||
|
checkIsVerifier();
|
||||||
|
getVerifierInfoFn();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检测是否是核销员
|
||||||
|
const checkIsVerifier = () => {
|
||||||
|
getCheckVerifier().then((res:any) =>{
|
||||||
|
if(!res.data){
|
||||||
|
uni.showToast({
|
||||||
|
title: '非核销员无此权限',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if(getCurrentPages().length > 1){
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
redirect({
|
||||||
|
url: '/app/pages/member/index',
|
||||||
|
mode: 'reLaunch'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}else{
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyInfo = ref({})
|
||||||
|
const getVerifierInfoFn = ()=>{
|
||||||
|
loading.value = true;
|
||||||
|
getVerifierInfo(code.value).then((res:any) =>{
|
||||||
|
verifyInfo.value = res.data;
|
||||||
|
loading.value = false;
|
||||||
|
}).catch(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false;
|
||||||
|
redirect({ url: '/app/pages/verify/index', param: {}, mode: 'redirectTo' })
|
||||||
|
}, 1000);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let isLoading = false;
|
||||||
|
const verifyFn = ()=>{
|
||||||
|
if(isLoading) return false;
|
||||||
|
isLoading = true;
|
||||||
|
|
||||||
|
verify(code.value).then((res:any) =>{
|
||||||
|
uni.showToast({
|
||||||
|
title: '核销成功',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
isLoading = false;
|
||||||
|
redirect({ url: '/app/pages/verify/index', param: {}, mode: 'redirectTo' })
|
||||||
|
}, 1000);
|
||||||
|
}).catch(() => {
|
||||||
|
isLoading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.confirmBtn{
|
||||||
|
background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
37
uni-app/src/app/pages/weapp/order_shipping.vue
Normal file
37
uni-app/src/app/pages/weapp/order_shipping.vue
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="themeColor()">
|
||||||
|
<view class="error-msg">{{errorMsg}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref} from 'vue';
|
||||||
|
import {redirect} from '@/utils/common';
|
||||||
|
import {onLoad} from '@dcloudio/uni-app'
|
||||||
|
import {getMsgJumpPath} from '@/app/api/system'
|
||||||
|
|
||||||
|
const outTradeNo = ref('')
|
||||||
|
const errorMsg = ref('')
|
||||||
|
|
||||||
|
onLoad((options: any) => {
|
||||||
|
if (options.merchant_trade_no) {
|
||||||
|
outTradeNo.value = options.merchant_trade_no;
|
||||||
|
getMsgJumpPathFn();
|
||||||
|
} else {
|
||||||
|
errorMsg.value = '缺少merchant_trade_no参数';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMsgJumpPathFn = () => {
|
||||||
|
getMsgJumpPath({
|
||||||
|
out_trade_no: outTradeNo.value,
|
||||||
|
}).then((res: any) => {
|
||||||
|
if(res.data && res.data.path){
|
||||||
|
// 跳转到设置的页面
|
||||||
|
redirect({url: '/' + res.data.path, mode: 'reLaunch'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user