first commit
|
|
@ -0,0 +1 @@
|
|||
VITE_API_BASE_URL= https://guess.hmily.club
|
||||
|
|
@ -0,0 +1 @@
|
|||
VITE_API_BASE_URL= https://guess.mini.zlgj168.com
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist.zip
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||
"version": "0.0",
|
||||
"configurations": [{
|
||||
"default" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"mp-weixin" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"type" : "uniCloud"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# 新疆圆梦竞彩
|
||||
|
||||
原型: https://modao.cc/proto/8TOOiUnsd0kabs4zw394j/sharing?view_mode=read_only
|
||||
|
||||
开发环境 appid(插件世界): wx4839fe39d3a4ab80
|
||||
|
||||
|
||||
- 管理后台
|
||||
https://guess.hmily.club/admin/
|
||||
admin
|
||||
admin
|
||||
|
||||
- 测试小程序: wxec1c45c29335c420
|
||||
- 正式小程序: wxb9fb3011c9317eef
|
||||
- 正式小程序2: wx49f828a7468772b8
|
||||
- apifox 接口文档: https://apifox.com/apidoc/shared-d3fd41c1-f0ad-47b1-a1ab-48f91ca3bc06
|
||||
|
||||
## 依赖说明
|
||||
|
||||
- node v16.20.2+
|
||||
- yarn 1.22.19+
|
||||
|
||||
## 开发说明
|
||||
|
||||
1. 安装依赖,并启动开发环境
|
||||
```
|
||||
yarn install
|
||||
yarn dev:mp-weixin
|
||||
```
|
||||
|
||||
2. 在小程序开发者工具中导入项目, 目录为 `项目目录/dist/dev/mp-weixin`
|
||||
|
||||
3. 以下页面代码完全一样,需要同步更新
|
||||
- activites 和 quizRecord
|
||||
- activeDetail 和 charts
|
||||
- login 和 about
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
DIR="/www/wwwroot/hetong-mobile/"
|
||||
SERVER_IP="8.218.100.178,"
|
||||
SERVER_ENV="ansible_host_key_checking=false ansible_user=root"
|
||||
if [ ! -z $SSH_PASSWORD ];then
|
||||
SERVER_ENV="ansible_host_key_checking=false ansible_user=root ansible_ssh_pass=$SSH_PASSWORD"
|
||||
fi
|
||||
|
||||
# 构建静态文件并打包
|
||||
if [ ! -f dist.zip ]; then
|
||||
# ./node_modules/.bin/vite build --config "./config/vite.config.prod.ts"
|
||||
# zip -r dist.zip dist -x "*node_modules/*" -x "*vendor/*"
|
||||
yarn build:h5
|
||||
zip -r dist.zip ./dist/ -x "*node_modules/*" -x "*vendor/*"
|
||||
fi
|
||||
|
||||
# 部署服务器
|
||||
time ansible all -i "${SERVER_IP}" -e "$SERVER_ENV" -m shell -a "chdir=/ mkdir -p ${DIR}"
|
||||
time ansible all -i "${SERVER_IP}" -e "$SERVER_ENV" -m shell -a "chattr -i ${DIR}/.user.ini || true; rm -f ${DIR}/{.user.ini,index.html,404.html,.htaccess} || true"
|
||||
time ansible all -i "${SERVER_IP}" -e "$SERVER_ENV" -m unarchive -a "src=./dist.zip dest=${DIR}"
|
||||
time ansible all -i "${SERVER_IP}" -e "$SERVER_ENV" -m shell -a "chdir=${DIR} chown -R www:www ."
|
||||
|
||||
if [[ -z $SSH_PASSWORD ]];then
|
||||
# time cd aliyun-fc-demo/supply-demand-test/ && s deploy
|
||||
time rm -rf ./dist/ ./dist.zip
|
||||
echo "success";
|
||||
fi
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"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:mp-xhs": "uni -p mp-xhs",
|
||||
"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",
|
||||
"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:mp-xhs": "uni build -p mp-xhs",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-app-plus": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-components": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-h5": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-alipay": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-baidu": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-jd": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-kuaishou": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-lark": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-qq": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-toutiao": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-weixin": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-mp-xhs": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-4010520240507001",
|
||||
"clipboard": "^2.0.11",
|
||||
"dayjs": "^1.11.11",
|
||||
"tiny-emitter": "^2.1.0",
|
||||
"uview-plus": "^3.1.41",
|
||||
"vue": "^3.4.21",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vue3-eventbus": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.4.8",
|
||||
"@dcloudio/uni-automator": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-cli-shared": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/uni-stacktracey": "3.0.0-alpha-4010520240507001",
|
||||
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-4010520240507001",
|
||||
"@vue/runtime-core": "^3.4.21",
|
||||
"sass": "^1.69.7",
|
||||
"sass-loader": "10",
|
||||
"vite": "5.2.8"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference types='@dcloudio/types' />
|
||||
import 'vue'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
|
||||
interface ComponentCustomOptions extends Hooks {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
<script>
|
||||
import dayjs from 'dayjs';
|
||||
import useAuthUser from '@/utils/hooks/useAuthUser';
|
||||
import { submitCode2Session } from '@/api/xinjiang_guess';
|
||||
|
||||
export default {
|
||||
globalData: {},
|
||||
onLaunch: function () {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: async function () {
|
||||
console.log('App Show')
|
||||
|
||||
if (uni.canIUse('getUpdateManager')) {
|
||||
const updateManager = uni.getUpdateManager();
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
if (res.hasUpdate) {
|
||||
updateManager.onUpdateReady(function () {
|
||||
wx.showModal({
|
||||
title: '更新提示',
|
||||
content: '新版本已经准备好,是否重启应用?',
|
||||
success: function (res) {
|
||||
// res: {errMsg: "showModal: ok", cancel: false, confirm: true}
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate()
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
updateManager.onUpdateFailed(function () {
|
||||
// 新的版本下载失败
|
||||
uni.showModal({
|
||||
title: '已经有新版本了哟~',
|
||||
content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~'
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
console.log('checkSession', this.checkSession());
|
||||
if (!this.checkSession()) {
|
||||
await this.login(true);
|
||||
}
|
||||
|
||||
console.log('App globalData', this.globalData);
|
||||
},
|
||||
onHide: function () {
|
||||
console.log('App Hide')
|
||||
},
|
||||
methods: {
|
||||
checkSession() {
|
||||
const expire_in = this.globalData.expire_in;
|
||||
if (!expire_in) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expire_in) {
|
||||
let isExpired = dayjs().isAfter(dayjs(expire_in))
|
||||
console.log('isExpired', isExpired);
|
||||
if (isExpired) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let willExpired = dayjs().add(6, 'hour').isAfter(dayjs(expire_in))
|
||||
console.log('willExpired', willExpired);
|
||||
if (willExpired) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
login() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const codeResp = await wx.login()
|
||||
const wxLoginResp = await submitCode2Session({ code: codeResp.code });
|
||||
const data = wxLoginResp.data;
|
||||
|
||||
this.globalData.api_token = data?.api_token;
|
||||
this.globalData.expire_in = data?.expire_in;
|
||||
this.globalData.user = data?.user;
|
||||
this.globalData.isLogin = !!this.globalData.api_token;
|
||||
this.globalData.isNeedBindPhone = !!this.globalData.user?.is_need_bind_phone;
|
||||
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
|
||||
if (page.$page) {
|
||||
console.log('current page: ', page.$page.fullPath);
|
||||
} else {
|
||||
console.log('current page: ', page.route);
|
||||
}
|
||||
|
||||
resolve();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/*每个页面公共css */
|
||||
@import "uview-plus/index.scss";
|
||||
|
||||
page {
|
||||
background-color: #f3f3f3;
|
||||
}
|
||||
|
||||
button,
|
||||
button[type=primary],
|
||||
button[plain],
|
||||
button[type=primary][plain],
|
||||
button::after {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
// 页面布局相关 外边距
|
||||
|
||||
.p-16 {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.pt-24 {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.m-16 {
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.text-red {
|
||||
color: #e91f35;
|
||||
}
|
||||
|
||||
.text-4e {
|
||||
color: #4e4e4e;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: #525252;
|
||||
}
|
||||
|
||||
.text-black {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.mb-10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.justify-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.text-base {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.text-xs {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.rounded-lg {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.block-box {
|
||||
padding: 12px;
|
||||
box-shadow: 0.5px 0.5px 1px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
// 公共样式封装
|
||||
.board {
|
||||
border-radius: 6px;
|
||||
background-color: #fff;
|
||||
padding: 12px 32px;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 26px 2px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #182c5f;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background-color: #d3d3d3;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary-sm {
|
||||
width: 60px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
padding: 0px !important;
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
border-radius: 20px !important;
|
||||
box-shadow: 1px 0.4px 1px #e91f35;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
margin-right: 16px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 多行文本最后一行展示省略号
|
||||
.ellipsis {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.nodata {
|
||||
margin-top: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.fixed{
|
||||
position: fixed;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
import useAuthUser from '@/utils/hooks/useAuthUser';
|
||||
|
||||
const http = uni.$u.http;
|
||||
|
||||
// 全局
|
||||
// 获取配置信息
|
||||
export const getConfigByKey = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/config-info`, { params, ...config });
|
||||
}
|
||||
|
||||
// 首页
|
||||
// 获取广告列表
|
||||
export const queryAds = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/ads`, { params, ...config });
|
||||
}
|
||||
// 获取最新竞猜
|
||||
export const queryLatestgame = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/latest-game`, { params, ...config });
|
||||
}
|
||||
// 获取推荐文章列表
|
||||
export const queryRecommendArticles = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/recommend-articles`, { params, ...config });
|
||||
}
|
||||
// 参与竞猜
|
||||
export const submitGuess = (params, config = {}) => {
|
||||
return http.post(`/api/miniprogram/games/${params.game}/join`, params, { ...config });
|
||||
}
|
||||
|
||||
// 登录注册
|
||||
// code2Session
|
||||
export const submitCode2Session = (params, config = {}) => {
|
||||
return http.post(`/api/miniprogram/code-to-session`, params, { ...config });
|
||||
}
|
||||
// 绑定手机号
|
||||
export const submitBindPhone = (params, config = {}) => {
|
||||
return http.post(`/api/miniprogram/users/bind-phone`, params, { ...config, custom: { toast: false, catch: true } });
|
||||
}
|
||||
// 刷新 token
|
||||
export const submitRefreshToken = (params, config = {}) => {
|
||||
return http.post(`/api/miniprogram/refresh-token`, params, { ...config });
|
||||
}
|
||||
|
||||
// 活动(竞猜)
|
||||
export const queryUserActivites = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/user-activities`, { params, ...config });
|
||||
}
|
||||
|
||||
// 资讯
|
||||
|
||||
// 文章分类
|
||||
export const getCategories = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/categories`, { params, ...config });
|
||||
}
|
||||
// 文章列表
|
||||
export const getArticlesList = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/articles`, { params, ...config });
|
||||
}
|
||||
// 文章详情
|
||||
export const getArticlesDetail = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/articles/${params.id}`, { params, ...config });
|
||||
}
|
||||
|
||||
// 活动列表
|
||||
export const queryAactivitiesList = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/activities`, { params, ...config });
|
||||
}
|
||||
|
||||
// 最新活动详情
|
||||
export const queryLatestActivitiesDetail = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/activities/latest-rank-list`, { params, ...config });
|
||||
}
|
||||
|
||||
// 活动详情
|
||||
export const queryActivitiesDetail = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/activities/${params.id}`, { params, ...config });
|
||||
}
|
||||
|
||||
// 竞猜列表
|
||||
export const queryGamesList = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/games`, { params, ...config });
|
||||
}
|
||||
// 排行榜
|
||||
export const queryRankList = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/activities/rank-list`, { params, ...config });
|
||||
}
|
||||
|
||||
// 用户-竞猜记录
|
||||
export const queryUserActivitiesList = (params, config = {}) => {
|
||||
return http.get('/api/miniprogram/user-activities', { params, ...config });
|
||||
}
|
||||
// 用户-获奖记录
|
||||
export const queryUserGiftsList = (params, config = {}) => {
|
||||
return http.get('/api/miniprogram/user-gifts', { params, ...config });
|
||||
}
|
||||
// 用户-奖品详情
|
||||
export const queryUserGiftsDetail = (params, config = {}) => {
|
||||
return http.get(`/api/miniprogram/user-gifts/${params.id}`, { params, ...config });
|
||||
}
|
||||
// 用户-领取奖品
|
||||
export const submitUserGiftsReceive = (params, config = {}) => {
|
||||
return http.post(`/api/miniprogram/user-gifts/${params.id}/receive`, params, { ...config });
|
||||
}
|
||||
// 用户-上传头像
|
||||
export const submitUploadAvatar = (params, config = {}) => {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// const headers = {
|
||||
// accept: 'application/json',
|
||||
// }
|
||||
|
||||
// const authUser = useAuthUser();
|
||||
// if (authUser.api_token) {
|
||||
// headers['authorization'] = `Bearer ${authUser.api_token}`
|
||||
// }
|
||||
|
||||
// let url = `${import.meta.env.VITE_API_BASE_URL}/api/miniprogram/upload-avatar`;
|
||||
// uni.uploadFile({
|
||||
// url: url,
|
||||
// filePath: params.filePath,
|
||||
// name: params.nameField || 'file', // 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容
|
||||
// formData: params.data || {},
|
||||
// header: headers,
|
||||
// responseType: 'json',
|
||||
// success(uploadFileRes) {
|
||||
// let res = {}
|
||||
// try {
|
||||
// res = JSON.parse(uploadFileRes.data);
|
||||
// resolve(res)
|
||||
// } catch (e) {
|
||||
// return reject(e);
|
||||
// }
|
||||
// },
|
||||
// fail(err) {
|
||||
// console.log(`request ${url} fail:`);
|
||||
// console.error(err);
|
||||
|
||||
// uni.showToast({
|
||||
// icon: 'none',
|
||||
// title: `请求服务失败: ${err.errMsg}`,
|
||||
// })
|
||||
// reject(err);
|
||||
// }
|
||||
// })
|
||||
// });
|
||||
return http.upload(`/api/miniprogram/upload-avatar`, {
|
||||
name: params.name || 'file',
|
||||
...params,
|
||||
...config,
|
||||
});
|
||||
}
|
||||
// 用户-更新个人资料
|
||||
export const submitUploadUserInfo = (params, config = {}) => {
|
||||
return http.post(`/api/miniprogram/user/update-info`, params, { ...config });
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
baseUrl: import.meta.env.VITE_API_BASE_URL,
|
||||
appInfo: {
|
||||
title: '猜了个球',
|
||||
version: "v1.0.0",
|
||||
},
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import { createSSRApp } from "vue";
|
||||
import uviewPlus from "uview-plus";
|
||||
|
||||
import App from "./App.vue";
|
||||
import { initRequest } from "@/utils/request/index";
|
||||
import eventBus from "vue3-eventbus";
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
dayjs.locale('zh-cn');
|
||||
|
||||
import mpShare from 'uview-plus/libs/mixin/mpShare'
|
||||
import mixin_common, { goToPage } from '@/utils/mixins/mixin_common';
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App);
|
||||
app.use(eventBus);
|
||||
app.use(uviewPlus);
|
||||
|
||||
initRequest(app);
|
||||
|
||||
app.mixin(mpShare);
|
||||
app.mixin(mixin_common);
|
||||
app.config.globalProperties.$goToPage = goToPage;
|
||||
|
||||
return {
|
||||
app,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
{
|
||||
"name" : "新疆圆梦竞彩",
|
||||
"appid" : "wx49f828a7468772b8",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : true,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "wx49f828a7468772b8",
|
||||
"setting" : {
|
||||
"urlCheck": false,
|
||||
"es6": true,
|
||||
"postcss": false,
|
||||
"minified": true,
|
||||
"newFeature": true,
|
||||
"bigPackageSizeSupport": true,
|
||||
"optimization":{"subPackages":true},
|
||||
"babelSetting": {
|
||||
"ignore": [],
|
||||
"disablePlugins": [],
|
||||
"outputPath": ""
|
||||
}
|
||||
},
|
||||
"lazyCodeLoading": "requiredComponents",
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "3",
|
||||
"h5" : {
|
||||
"router" : {
|
||||
"mode" : "history"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"id": "xlh-table",
|
||||
"name": "App、小程序table表格、跨行表格",
|
||||
"displayName": "App、小程序table表格、跨行表格",
|
||||
"version": "1.0.0",
|
||||
"description": "适用于各端的表格组件、跨行表格组件",
|
||||
"keywords": [
|
||||
"Table、table、xlh-table"
|
||||
],
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
<template>
|
||||
<view class="page-login">
|
||||
<view class="info">
|
||||
<image class="img" :src="mini_logo"></image>
|
||||
<view class="appname" v-if="!isLoginPage">{{ config.appInfo.title }}</view>
|
||||
<view class="version" v-if="!isLoginPage">版本号 {{ config.appInfo.version }}</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isLoginPage">
|
||||
<button class="btn-primary btn-first" openType="getPhoneNumber" @getphonenumber="handleAuth"
|
||||
:loading="submitBindPhoneLoading" :disabled="checkAgreement === false">手机号一键登录/注册</button>
|
||||
<button class="btn-primary bg-white text-black" @click="goToPreviousPage()">暂不注册</button>
|
||||
</view>
|
||||
|
||||
<view class="agreement">
|
||||
<up-checkbox-group class="agreement-check" placement="column" v-if="isLoginPage">
|
||||
<up-checkbox :size="14" :labelSize="14" :customStyle="{ marginBottom: '8px' }" label="" name="agree"
|
||||
:checked="checkAgreement" @change="agreementGroupChange">
|
||||
</up-checkbox>
|
||||
</up-checkbox-group>
|
||||
<view class="agreement-list"
|
||||
:class="{ 'agreement-list-about': isLoginPage ? false : true, 'agreement-list-left': isLoginPage ? true : false }">
|
||||
<text @click="checkAgreement = !checkAgreement" v-if="isLoginPage">我已知晓本应用仅用于竞猜娱乐使用,已阅读并同意</text>
|
||||
<text class="link" @click="showUserAgreement">《用户协议》</text>
|
||||
<text class="link" @click="showPrivacyPolicy" v-if="false">《隐私政策》</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<up-modal :show="showModalVisible" :width="335" :closeOnClickOverlay="true" :showConfirmButton="false"
|
||||
:showCancelButton="false" @close="showModalVisible = false">
|
||||
<view class="modal-content">
|
||||
<view class="title">{{ title }}</view>
|
||||
<mp-html :content="content" class="content"></mp-html>
|
||||
</view>
|
||||
</up-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import config from '@/common/config'
|
||||
import useAuthUser from '@/utils/hooks/useAuthUser';
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import {
|
||||
getConfigByKey,
|
||||
submitBindPhone,
|
||||
} from '@/api/xinjiang_guess'
|
||||
|
||||
const isLoginPage = ref(true);
|
||||
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
if (page.route.includes('login')) {
|
||||
isLoginPage.value = true;
|
||||
} else {
|
||||
isLoginPage.value = false;
|
||||
}
|
||||
|
||||
const checkAgreement = ref(false);
|
||||
const submitBindPhoneLoading = ref(false);
|
||||
const loading = ref(false);
|
||||
const showModalVisible = ref(false);
|
||||
const mini_logo = ref('');
|
||||
const user_agreement = ref('');
|
||||
const privacy_policy = ref('');
|
||||
const title = ref('');
|
||||
const content = ref('');
|
||||
|
||||
async function getConfigInfo() {
|
||||
loading.value = true;
|
||||
const resp = await getConfigByKey({
|
||||
key: 'mini_logo,user_agreement,privacy_policy',
|
||||
});
|
||||
loading.value = false;
|
||||
|
||||
mini_logo.value = resp.data.mini_logo;
|
||||
user_agreement.value = resp.data.user_agreement;
|
||||
privacy_policy.value = resp.data.privacy_policy;
|
||||
}
|
||||
|
||||
const pageQuery = ref({});
|
||||
onLoad(async (query) => {
|
||||
pageQuery.value = query;
|
||||
setTimeout(() => {
|
||||
getConfigInfo();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
function showUserAgreement() {
|
||||
title.value = '用户协议';
|
||||
content.value = user_agreement.value;
|
||||
showModalVisible.value = true;
|
||||
}
|
||||
function showPrivacyPolicy() {
|
||||
title.value = '隐私政策';
|
||||
content.value = privacy_policy.value;
|
||||
showModalVisible.value = true;
|
||||
}
|
||||
function agreementGroupChange(checked) {
|
||||
checkAgreement.value = checked;
|
||||
}
|
||||
|
||||
async function handleAuth(e) {
|
||||
switch (e.detail.errMsg) {
|
||||
default:
|
||||
uni.showToast({
|
||||
title: '获取手机号失败: ' + e.detail.errMsg,
|
||||
icon: 'none',
|
||||
});
|
||||
console.log(e);
|
||||
return;
|
||||
case 'getPhoneNumber:fail user deny':
|
||||
uni.showToast({
|
||||
title: '获取手机号失败',
|
||||
icon: 'none',
|
||||
});
|
||||
return;
|
||||
break;
|
||||
case 'getPhoneNumber:ok':
|
||||
break;
|
||||
}
|
||||
|
||||
const authUser = useAuthUser();
|
||||
|
||||
try {
|
||||
submitBindPhoneLoading.value = true;
|
||||
submitBindPhone({
|
||||
code: e.detail.code
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res);
|
||||
const app = getApp();
|
||||
app.login(true).then(res => {
|
||||
goToPreviousPage();
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
goToPreviousPage();
|
||||
// uni.$u.toast(err.message);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
goToPreviousPage();
|
||||
} finally {
|
||||
submitBindPhoneLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function goToPreviousPage() {
|
||||
let indexUrl = '/pages/index/index';
|
||||
let url = indexUrl;
|
||||
|
||||
switch (pageQuery.value.previous) {
|
||||
case 'index':
|
||||
url = indexUrl;
|
||||
break;
|
||||
case 'setting':
|
||||
url = '/packages/pages/setting/setting';
|
||||
break;
|
||||
case 'my':
|
||||
url = '/pages/my/index';
|
||||
break;
|
||||
case 'custom':
|
||||
url = pageQuery.value.url || indexUrl;
|
||||
break;
|
||||
case 'activeDetail':
|
||||
url = `${pageQuery.value.url}?id=${pageQuery.value.id}` || indexUrl;
|
||||
break;
|
||||
};
|
||||
console.log('login to previous', pageQuery.value.previous);
|
||||
console.log('login to previous url', url);
|
||||
|
||||
uni.reLaunch({
|
||||
url: url,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 80px;
|
||||
margin-bottom: 50px;
|
||||
|
||||
.img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.appname,
|
||||
.version {
|
||||
margin-top: 20px;
|
||||
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
width: 280px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
padding: 0 !important;
|
||||
font-size: 12px;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.btn-first {
|
||||
background-color: #1d2b5c;
|
||||
color: #fff;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.agreement {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.u-checkbox-group {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.agreement-list-about {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
bottom: 40px;
|
||||
width: 100%;
|
||||
|
||||
font-size: 12px;
|
||||
color: #958aeb !important;
|
||||
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.agreement-list {
|
||||
display: inline;
|
||||
justify-content: center;
|
||||
|
||||
bottom: 40px;
|
||||
width: 100%;
|
||||
|
||||
text-align: center;
|
||||
|
||||
.link {
|
||||
font-weight: bold;
|
||||
color: #958aeb !important;
|
||||
}
|
||||
}
|
||||
|
||||
.agreement-list-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 75vh;
|
||||
overflow: scroll;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
<template>
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :up="{
|
||||
empty: {
|
||||
use: true,
|
||||
}
|
||||
}">
|
||||
<view class="page-gifts">
|
||||
<view v-for="(item, index) in list" :key="index">
|
||||
<view class="card-box" v-if="list.length">
|
||||
<view class="card-image-box" :class="{ 'last': index === list.length - 1 }" v-if="item.gift_logo">
|
||||
<image class="card-image" :src="item.gift_logo"></image>
|
||||
<view class="card-info-box">
|
||||
<view class="card-info">
|
||||
<view class="card-info-title">{{ item.gift_name }}</view>
|
||||
<view class="card-info-publish_time">{{ item.activity_name }}-第{{ item.gift_rank }}名</view>
|
||||
</view>
|
||||
|
||||
<view class="card-btns"
|
||||
@click="$goToPage({ url: 'packages/pages/awardDetail/awardDetail', params: { id: item.id } })">
|
||||
<up-button
|
||||
:customStyle="{ margin: 0, width: '75px', height: '28px', backgroundColor: '#5fb358', color: '#fff', }"
|
||||
shape="circle" text="领取" v-if="item.state == 0"></up-button>
|
||||
<up-button
|
||||
:customStyle="{ margin: 0, width: '75px', height: '28px', backgroundColor: '#F0F0F0', color: '#000', }"
|
||||
shape="circle" text="查看" v-else></up-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { queryUserGiftsList } from "@/api/xinjiang_guess.js";
|
||||
import { ref } from "vue";
|
||||
|
||||
onShow(() => {
|
||||
getMescroll().resetUpScroll();
|
||||
})
|
||||
|
||||
function getData(page = 1, per_page = 10) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const res = await queryUserGiftsList({ page, per_page });
|
||||
|
||||
resolve(res.data.gifts);
|
||||
});
|
||||
}
|
||||
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||
|
||||
const list = ref([]);
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' && getData(mescroll.num, mescroll.size).then(data => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data;
|
||||
}
|
||||
if (mescroll.num == 1) list.value = []; // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData); //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
|
||||
}).catch(() => {
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-gifts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
|
||||
>view {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-box {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
width: calc(100% - 24px);
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
|
||||
.card-title-box {
|
||||
padding-left: 12px;
|
||||
border-left: 4px solid #D8524C;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.more {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-image-box,
|
||||
.card-content-box {}
|
||||
|
||||
.card-image-box {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.card-image {
|
||||
flex-shrink: 0;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-info-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: flex-start;
|
||||
gap: 4px;
|
||||
|
||||
&-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&-publish_time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.last {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.card-btns {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
<template>
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :up="{
|
||||
empty: {
|
||||
use: false,
|
||||
}
|
||||
}">
|
||||
<view class="page-gift-detail">
|
||||
<view class="card-box">
|
||||
<view class="card-image-box last" v-if="detail.gift_logo">
|
||||
<image class="card-image" :src="detail.gift_logo"></image>
|
||||
<view class="card-info-box">
|
||||
<view class="card-info">
|
||||
<view class="card-info-title">{{ detail.gift_name }}</view>
|
||||
<view class="card-info-publish_time">{{ detail.activity_name }}-第{{ detail.gift_rank }}名</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-box" v-if="detail.state == 0 && detail.gift_explain">
|
||||
<view class="text-sm text-balck">领奖说明</view>
|
||||
<!-- eslint-disable-next-line -->
|
||||
<view class="gift_explain text-xs text-4e" v-text="detail.gift_explain"></view>
|
||||
</view>
|
||||
|
||||
<view class="card-box card-form">
|
||||
<up-form labelPosition="left" labelWidth="5em" :model="form" :rules="rules" ref="uFormRef">
|
||||
<up-form-item label="收货人" prop="consignee">
|
||||
<up-input :readonly="detail.state != 0" v-model="form.consignee" border="none" placeholder="请输入收货人姓名"
|
||||
clearable></up-input>
|
||||
</up-form-item>
|
||||
<up-form-item label="手机号" prop="phone">
|
||||
<up-input :readonly="detail.state != 0" v-model="form.phone" border="none" placeholder="请输入手机号"
|
||||
clearable></up-input>
|
||||
</up-form-item>
|
||||
<up-form-item label="收货地址" prop="address">
|
||||
<up-input :readonly="detail.state != 0" v-model="form.address" border="none" placeholder="请输入收货地址"
|
||||
clearable></up-input>
|
||||
</up-form-item>
|
||||
</up-form>
|
||||
|
||||
<view class="mt-10" v-if="detail.state == 0">
|
||||
<button class="btn-save btn text-white text-xs" @click="submit">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-box card-form" v-if="detail.state == 1">
|
||||
<up-form labelPosition="left" labelWidth="5em" :model="form">
|
||||
<up-form-item label="发货状态">
|
||||
<view class="text-4e">待发货</view>
|
||||
</up-form-item>
|
||||
</up-form>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="card-box card-form" v-if="detail.state == 2">
|
||||
<up-form labelPosition="left" labelWidth="5em" :model="form">
|
||||
<up-form-item label="快递公司" prop="shipping_company">
|
||||
<up-input v-model="detail.shipping_company" border="none" readonly></up-input>
|
||||
</up-form-item>
|
||||
<up-form-item class="shipping_number" label="快递单号" prop="shipping_number">
|
||||
<text>{{ detail.shipping_number }}</text>
|
||||
<up-copy :content="detail.shipping_number">
|
||||
<image class="copy" mode="aspectFit" src="@/static/icons/copy.svg" />
|
||||
</up-copy>
|
||||
</up-form-item>
|
||||
</up-form>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { queryUserGiftsDetail, submitUserGiftsReceive } from '@/api/xinjiang_guess.js'
|
||||
import { ref } from "vue";
|
||||
|
||||
|
||||
const detail = ref({});
|
||||
async function getUserGiftsDetail(gift_id) {
|
||||
const res = await queryUserGiftsDetail({ id: gift_id, })
|
||||
detail.value = res.data;
|
||||
detail.value.shipping_company = detail.value.shipping_company || '-';
|
||||
detail.value.shipping_number = detail.value.shipping_number || '-';
|
||||
|
||||
form.value.consignee = detail.value.consignee;
|
||||
form.value.phone = detail.value.phone;
|
||||
form.value.address = detail.value.address;
|
||||
}
|
||||
|
||||
const form = ref({
|
||||
id: "",
|
||||
consignee: "",
|
||||
phone: "",
|
||||
address: "",
|
||||
});
|
||||
|
||||
const rules = {
|
||||
consignee: [
|
||||
{
|
||||
required: true,
|
||||
message: "请填写收货人",
|
||||
trigger: ["blur", "change"],
|
||||
},
|
||||
],
|
||||
phone: [
|
||||
{
|
||||
required: true,
|
||||
message: "请填写手机号",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
address: [
|
||||
{
|
||||
required: true,
|
||||
message: "请填写收货地址",
|
||||
trigger: "blur",
|
||||
},
|
||||
],
|
||||
};
|
||||
const uFormRef = ref(null);
|
||||
function submit() {
|
||||
uFormRef.value
|
||||
.validate()
|
||||
.then(async (valid) => {
|
||||
if (!valid) return;
|
||||
const res = await submitUserGiftsReceive(form.value)
|
||||
if (res.code === 200) {
|
||||
uni.$u.toast("领取成功");
|
||||
|
||||
getUserGiftsDetail(form.value.id);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
});
|
||||
}
|
||||
|
||||
onLoad(async (query) => {
|
||||
form.value.id = query.id;
|
||||
});
|
||||
|
||||
function getData(page = 1, per_page = 10) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const res = await getUserGiftsDetail(form.value.id);
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||
|
||||
const list = ref([]);
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' && getData(mescroll.num, mescroll.size).then(data => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data;
|
||||
}
|
||||
if (mescroll.num == 1) list.value = []; // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData); //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
|
||||
}).catch(() => {
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-gift-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
|
||||
.gift_explain {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.shipping_number,
|
||||
.u-form-item__body__right__content__slot {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.copy {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 84px;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
border-radius: 16px;
|
||||
background-color: #1d2b5c;
|
||||
margin-top: 20px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.card-box {
|
||||
flex: 1;
|
||||
|
||||
padding: 12px;
|
||||
width: calc(100% - 24px);
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
|
||||
.card-title-box {
|
||||
padding-left: 12px;
|
||||
border-left: 4px solid #D8524C;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.more {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-image-box,
|
||||
.card-content-box {
|
||||
padding: 12px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.card-image-box {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.card-image {
|
||||
flex-shrink: 0;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-info-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: flex-start;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-info {
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: flex-start;
|
||||
gap: 4px;
|
||||
|
||||
&-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&-publish_time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.last {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.card-btns {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.card-form {
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,334 @@
|
|||
<template>
|
||||
<view>
|
||||
<up-navbar :title="`${contractDetail ? (contractDetail?.hetong?.title || '签署合同') : '签署合同'}`" leftIcon=""
|
||||
:autoBack="false">
|
||||
</up-navbar>
|
||||
|
||||
<view v-if="!contractDetail">
|
||||
<view class="card header-card">
|
||||
<view class="title">Contract document not found</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="contractDetail" style="padding-bottom: 110px;">
|
||||
<view class="card header-card">
|
||||
<!--eslint-disable-->
|
||||
<view class="content"
|
||||
v-html="contractDetail?.hetong?.content || `${langKey?.lang_remark_text || '合同内容为空'}`">
|
||||
</view>
|
||||
<view class="content" v-if="contractDetail?.remark">
|
||||
<view>{{ langKey?.lang_remark_text || '备注' }}: {{ contractDetail?.remark || '-' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card" v-if="contractDetail?.sign_img">
|
||||
<view>
|
||||
<view>{{ langKey?.lang_signed_text || '签名' }}: </view>
|
||||
<up-image style="border: 1px solid #fff;" width="160" height="90" mode="widthFix"
|
||||
:show-loading="true" :src="contractDetail?.sign_img || signatureUrl"></up-image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card" v-if="!contractDetail.sign_img">
|
||||
<view class="title">
|
||||
<view>
|
||||
{{ langKey?.lang_status_text || '签署状态' }}: {{ isNeedSign ? `${langKey?.lang_unsigned_text ||
|
||||
'需要签名'}` : `${langKey?.lang_signed_text || '已签名'}` }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<up-image style="border: 1px solid #fff;" width="160" height="90" mode="widthFix" :show-loading="true"
|
||||
:src="signatureUrl" v-if="!isNeedSign"></up-image>
|
||||
</view>
|
||||
|
||||
<view class="buttom-box" v-if="!contractDetail?.sign_img">
|
||||
<view class="bottom-tips">
|
||||
<up-checkbox-group v-model="contractList" @change="checkboxChange" placement="column">
|
||||
<up-checkbox size="14" labelSize="14" labelColor="#999999" :customStyle="{ fontWeight: 400 }"
|
||||
:label="`${langKey?.lang_tip_checkbox_text || '注:请认真确认合同后进行签署'}`" name="agree">
|
||||
</up-checkbox>
|
||||
</up-checkbox-group>
|
||||
</view>
|
||||
<view class="buttom-btn">
|
||||
<up-button class="btn btn-left" type="primary" :text="`${langKey?.lang_sign_button_text || '签署'}`"
|
||||
@click="toSignaturePage" :disabled="needReadContract"></up-button>
|
||||
<up-button class="btn btn-right" type="primary" :text="`${langKey?.lang_sign_button_text || '提交'}`"
|
||||
:loading="submitLoading" @click="submit" :disabled="disableSubmit"></up-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getInitLangKey,
|
||||
getContractDetail,
|
||||
submitSignContract
|
||||
} from "@/api/contract.js";
|
||||
import load_langkey from "@/utils/mixins/load_langkey";
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
load_langkey
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
contractDetail: null,
|
||||
contractList: [],
|
||||
needReadContract: true,
|
||||
isNeedSign: true,
|
||||
signatureUrl: '',
|
||||
|
||||
submitForm: {},
|
||||
disableSubmit: true,
|
||||
submitLoading: false,
|
||||
|
||||
rules: {
|
||||
urlkey: {
|
||||
type: "number",
|
||||
required: false,
|
||||
message: "请提供合同信息",
|
||||
trigger: ["blur", "change"],
|
||||
},
|
||||
mobile: [{
|
||||
required: false,
|
||||
message: "请输入手机号",
|
||||
trigger: ["change", "blur"],
|
||||
},
|
||||
{
|
||||
// 自定义验证函数,见上说明
|
||||
validator: (rule, value, callback) => {
|
||||
// 上面有说,返回true表示校验通过,返回false表示不通过
|
||||
// uni.$u.test.mobile()就是返回true或者false的
|
||||
return uni.$u.test.mobile(value);
|
||||
},
|
||||
message: "手机号码不正确",
|
||||
// 触发器可以同时用blur和change
|
||||
trigger: ["change", "blur"],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
onReady: function () {
|
||||
uni.removeStorageSync('sign_res');
|
||||
},
|
||||
onLoad: async function (options) {
|
||||
if (options.urlkey) {
|
||||
uni.removeStorageSync('urlkey');
|
||||
uni.setStorageSync('urlkey', options.urlkey);
|
||||
}
|
||||
|
||||
const urlkey = uni.getStorageSync('urlkey');
|
||||
if (urlkey) {
|
||||
this.query.urlkey = urlkey
|
||||
}
|
||||
|
||||
if (this.query.urlkey) {
|
||||
this.loadDetail()
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
const sign_res = uni.getStorageSync('sign_res')
|
||||
|
||||
if (sign_res) {
|
||||
this.isNeedSign = sign_res.isEmpty;
|
||||
this.signatureUrl = sign_res.tempFilePath;
|
||||
|
||||
this.needReadContract = true;
|
||||
this.disableSubmit = true;
|
||||
if (!this.isNeedSign) {
|
||||
this.contractList.push('agree')
|
||||
this.needReadContract = false;
|
||||
this.disableSubmit = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async loadDetail() {
|
||||
try {
|
||||
const res = await getContractDetail({
|
||||
urlkey: this.query.urlkey,
|
||||
});
|
||||
|
||||
this.contractDetail = res.data;
|
||||
console.log('detail', this.contractDetail);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
},
|
||||
checkboxChange(n) {
|
||||
this.contractList = n;
|
||||
if (this.contractList.includes('agree')) {
|
||||
this.needReadContract = false;
|
||||
} else {
|
||||
this.needReadContract = true;
|
||||
this.disableSubmit = true;
|
||||
}
|
||||
},
|
||||
toSignaturePage() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/signature/signature',
|
||||
})
|
||||
},
|
||||
submit() {
|
||||
this.submitLoading = true;
|
||||
try {
|
||||
(async () => {
|
||||
const res = await submitSignContract({
|
||||
urlkey: this.query.urlkey,
|
||||
sign_img: this.signatureUrl,
|
||||
});
|
||||
|
||||
console.log(res, '保存结果')
|
||||
uni.$u.toast(res.msg || "登记成功");
|
||||
|
||||
this.loadDetail();
|
||||
})();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
this.submitLoading = false;
|
||||
};
|
||||
// this.$refs.userInfoForm
|
||||
// .validate()
|
||||
// .then((res) => {
|
||||
// try {
|
||||
// (async () => {
|
||||
// const res = await postInvite(this.userInfo);
|
||||
// this.$refs.uToast?.show({
|
||||
// type: "success",
|
||||
// message: "登记成功",
|
||||
// });
|
||||
// this.showFormModalVisible = false;
|
||||
// this.showQrCodeModalVisible = true;
|
||||
// this.submitLoading = false;
|
||||
// })();
|
||||
// } catch (e) {
|
||||
// console.error(e);
|
||||
// } finally {}
|
||||
// })
|
||||
// .catch((errors) => {
|
||||
// console.log(errors);
|
||||
// uni.$u.toast(errors[0]?.message);
|
||||
// });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page {
|
||||
padding: 24rpx 32rpx;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 0 11px;
|
||||
margin-top: 10px;
|
||||
padding: 12px 16px;
|
||||
|
||||
border-radius: 12px;
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
.header-card {
|
||||
/* #ifdef H5 */
|
||||
--status-bar-height: 44px;
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
--status-bar-height: 68px;
|
||||
/* #endif */
|
||||
|
||||
// width: calc(353px - 16px * 2); // mobile
|
||||
flex-shrink: 0;
|
||||
|
||||
margin: 0 11px;
|
||||
margin-top: calc(var(--status-bar-height) + 10px);
|
||||
}
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 16px;
|
||||
width: 321px;
|
||||
}
|
||||
|
||||
.buttom-box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
background-color: #fff;
|
||||
|
||||
// width: 375px;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
flex-shrink: 0;
|
||||
|
||||
padding: 8px 16px;
|
||||
|
||||
.bottom-tips {
|
||||
width: calc(100% - 16px * 2);
|
||||
color: #999;
|
||||
text-align: left;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.buttom-btn {
|
||||
margin-top: 10px;
|
||||
|
||||
width: calc(100% - 16px * 2);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
color: #000;
|
||||
|
||||
.btn {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.btn-left {
|
||||
width: 107px;
|
||||
height: 40px;
|
||||
|
||||
border-radius: 20px;
|
||||
background: rgba(44, 44, 44, 0.50);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-right {
|
||||
width: 225px;
|
||||
height: 40px;
|
||||
|
||||
border-radius: 20px;
|
||||
background: #4597F7;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background-color: #fff;
|
||||
|
||||
padding: 40rpx 32rpx;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 40rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-btn {
|
||||
background-color: #779aef;
|
||||
color: #fff;
|
||||
border-radius: 50rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
<template>
|
||||
<view class="page-login">
|
||||
<view class="info">
|
||||
<image class="img" :src="mini_logo"></image>
|
||||
<view class="appname" v-if="!isLoginPage">{{ config.appInfo.title }}</view>
|
||||
<view class="version" v-if="!isLoginPage">版本号 {{ config.appInfo.version }}</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isLoginPage">
|
||||
<button class="btn-primary btn-first" openType="getPhoneNumber" @getphonenumber="handleAuth"
|
||||
:loading="submitBindPhoneLoading" :disabled="checkAgreement === false">手机号一键登录/注册</button>
|
||||
<button class="btn-primary bg-white text-black" @click="goToPreviousPage()">暂不注册</button>
|
||||
</view>
|
||||
|
||||
<view class="agreement">
|
||||
<up-checkbox-group class="agreement-check" placement="column" v-if="isLoginPage">
|
||||
<up-checkbox :size="14" :labelSize="14" :customStyle="{ marginBottom: '8px' }" label="" name="agree"
|
||||
:checked="checkAgreement" @change="agreementGroupChange">
|
||||
</up-checkbox>
|
||||
</up-checkbox-group>
|
||||
<view class="agreement-list"
|
||||
:class="{ 'agreement-list-about': isLoginPage ? false : true, 'agreement-list-left': isLoginPage ? true : false }">
|
||||
<text @click="checkAgreement = !checkAgreement" v-if="isLoginPage">我已知晓本应用仅用于竞猜娱乐使用,已阅读并同意</text>
|
||||
<text class="link" @click="showUserAgreement">《用户协议》</text>
|
||||
<text class="link" @click="showPrivacyPolicy" v-if="false">《隐私政策》</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<up-modal :show="showModalVisible" :width="335" :closeOnClickOverlay="true" :showConfirmButton="false"
|
||||
:showCancelButton="false" @close="showModalVisible = false">
|
||||
<view class="modal-content">
|
||||
<view class="title">{{ title }}</view>
|
||||
<mp-html :content="content" class="content"></mp-html>
|
||||
</view>
|
||||
</up-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import config from '@/common/config'
|
||||
import useAuthUser from '@/utils/hooks/useAuthUser';
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import {
|
||||
getConfigByKey,
|
||||
submitBindPhone,
|
||||
} from '@/api/xinjiang_guess'
|
||||
|
||||
const isLoginPage = ref(true);
|
||||
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
if (page.route.includes('login')) {
|
||||
isLoginPage.value = true;
|
||||
} else {
|
||||
isLoginPage.value = false;
|
||||
}
|
||||
|
||||
const checkAgreement = ref(false);
|
||||
const submitBindPhoneLoading = ref(false);
|
||||
const loading = ref(false);
|
||||
const showModalVisible = ref(false);
|
||||
const mini_logo = ref('');
|
||||
const user_agreement = ref('');
|
||||
const privacy_policy = ref('');
|
||||
const title = ref('');
|
||||
const content = ref('');
|
||||
|
||||
async function getConfigInfo() {
|
||||
loading.value = true;
|
||||
const resp = await getConfigByKey({
|
||||
key: 'mini_logo,user_agreement,privacy_policy',
|
||||
});
|
||||
loading.value = false;
|
||||
|
||||
mini_logo.value = resp.data.mini_logo;
|
||||
user_agreement.value = resp.data.user_agreement;
|
||||
privacy_policy.value = resp.data.privacy_policy;
|
||||
}
|
||||
|
||||
const pageQuery = ref({});
|
||||
onLoad(async (query) => {
|
||||
pageQuery.value = query;
|
||||
setTimeout(() => {
|
||||
getConfigInfo();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
function showUserAgreement() {
|
||||
title.value = '用户协议';
|
||||
content.value = user_agreement.value;
|
||||
showModalVisible.value = true;
|
||||
}
|
||||
function showPrivacyPolicy() {
|
||||
title.value = '隐私政策';
|
||||
content.value = privacy_policy.value;
|
||||
showModalVisible.value = true;
|
||||
}
|
||||
function agreementGroupChange(checked) {
|
||||
checkAgreement.value = checked;
|
||||
}
|
||||
|
||||
async function handleAuth(e) {
|
||||
switch (e.detail.errMsg) {
|
||||
default:
|
||||
uni.showToast({
|
||||
title: '获取手机号失败: ' + e.detail.errMsg,
|
||||
icon: 'none',
|
||||
});
|
||||
console.log(e);
|
||||
return;
|
||||
case 'getPhoneNumber:fail user deny':
|
||||
uni.showToast({
|
||||
title: '获取手机号失败',
|
||||
icon: 'none',
|
||||
});
|
||||
return;
|
||||
break;
|
||||
case 'getPhoneNumber:ok':
|
||||
break;
|
||||
}
|
||||
|
||||
const authUser = useAuthUser();
|
||||
|
||||
try {
|
||||
submitBindPhoneLoading.value = true;
|
||||
submitBindPhone({
|
||||
code: e.detail.code
|
||||
})
|
||||
.then(res => {
|
||||
console.log(res);
|
||||
const app = getApp();
|
||||
app.login(true).then(res => {
|
||||
goToPreviousPage();
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
goToPreviousPage();
|
||||
// uni.$u.toast(err.message);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
goToPreviousPage();
|
||||
} finally {
|
||||
submitBindPhoneLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function goToPreviousPage() {
|
||||
let indexUrl = '/pages/index/index';
|
||||
let url = indexUrl;
|
||||
|
||||
switch (pageQuery.value.previous) {
|
||||
case 'index':
|
||||
url = indexUrl;
|
||||
break;
|
||||
case 'setting':
|
||||
url = '/packages/pages/setting/setting';
|
||||
break;
|
||||
case 'my':
|
||||
url = '/pages/my/index';
|
||||
break;
|
||||
case 'custom':
|
||||
url = pageQuery.value.url || indexUrl;
|
||||
break;
|
||||
case 'activeDetail':
|
||||
url = `${pageQuery.value.url}?id=${pageQuery.value.id}` || indexUrl;
|
||||
break;
|
||||
};
|
||||
console.log('login to previous', pageQuery.value.previous);
|
||||
console.log('login to previous url', url);
|
||||
|
||||
uni.reLaunch({
|
||||
url: url,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-top: 80px;
|
||||
margin-bottom: 50px;
|
||||
|
||||
.img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.appname,
|
||||
.version {
|
||||
margin-top: 20px;
|
||||
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
width: 280px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
padding: 0 !important;
|
||||
font-size: 12px;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.btn-first {
|
||||
background-color: #1d2b5c;
|
||||
color: #fff;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.agreement {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.u-checkbox-group {
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.agreement-list-about {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
bottom: 40px;
|
||||
width: 100%;
|
||||
|
||||
font-size: 12px;
|
||||
color: #958aeb !important;
|
||||
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.agreement-list {
|
||||
display: inline;
|
||||
justify-content: center;
|
||||
|
||||
bottom: 40px;
|
||||
width: 100%;
|
||||
|
||||
text-align: center;
|
||||
|
||||
.link {
|
||||
font-weight: bold;
|
||||
color: #958aeb !important;
|
||||
}
|
||||
}
|
||||
|
||||
.agreement-list-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 75vh;
|
||||
overflow: scroll;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<template>
|
||||
<view class="bg-white wrap">
|
||||
<view class="image mb-10" v-if="data.cover">
|
||||
<image class="image" :src="data.cover" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="p-16 title-bar flex-1" v-if="data">
|
||||
<view class="text-base text-black">{{ data.title }}</view>
|
||||
<view class="flex justify-between text-9f text-sm title">
|
||||
<view class="">{{ data.published_at }}</view>
|
||||
<view class="" v-if="data.source">来源: {{ data.source || '-' }}</view>
|
||||
</view>
|
||||
<mp-html class="content text-sm text" :content="data.content"></mp-html>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { getArticlesDetail } from '@/api/xinjiang_guess.js';
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
const id = ref('');;
|
||||
const data = ref({})
|
||||
|
||||
onLoad((query) => {
|
||||
id.value = query.id;
|
||||
getArticlesDetail({ id: id.value }).then((res) => {
|
||||
data.value = res.data;
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.image {
|
||||
width: 100vw;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.text-9f {
|
||||
color: #9f9f9f;
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 12px 0 20px;
|
||||
}
|
||||
|
||||
.text {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow: scroll;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
<template>
|
||||
<view class="page-activates">
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :down="{
|
||||
auto: false,
|
||||
}" :up="{
|
||||
empty: {
|
||||
use: true,
|
||||
}
|
||||
}">
|
||||
<view class="activate-box" v-for="(item, index) in list" :key="index"
|
||||
@click="$goToPage({ url: 'packages/pages/activeDetail/activeDetail', params: { id: item.id } })">
|
||||
<image class="activate-cover" mode="aspectFill" :src="item.cover" />
|
||||
<image class="state-image" mode="aspectFit" src="/static/images/active-processing.svg"
|
||||
v-if="item.state === 1" />
|
||||
<image class="state-image" mode="aspectFit" src="/static/images/active-finished.svg" v-if="item.state === 2" />
|
||||
<view class="gift-tag" v-if="item.has_gift">已获奖</view>
|
||||
|
||||
<view class="activate-info">
|
||||
<view class="title">{{ item.name }}</view>
|
||||
<view class="time">
|
||||
<view>{{ item.start_at }}</view>
|
||||
<view>至</view>
|
||||
<view>{{ item.end_at }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { queryAactivitiesList, queryUserActivitiesList } from '@/api/xinjiang_guess.js'
|
||||
import dayjs from 'dayjs';
|
||||
import { ref } from "vue";
|
||||
|
||||
const isActivitePage = ref(false);
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
if (isActivitePage) {
|
||||
isActivitePage.value = true;
|
||||
} else {
|
||||
isActivitePage.value = false;
|
||||
}
|
||||
|
||||
const pageReady = ref(false);
|
||||
|
||||
onLoad((query) => {
|
||||
console.log(query);
|
||||
|
||||
switch (query.source) {
|
||||
default:
|
||||
isActivitePage.value = true;
|
||||
break;
|
||||
case 'mine':
|
||||
isActivitePage.value = false;
|
||||
break;
|
||||
}
|
||||
pageReady.value = true;
|
||||
getMescroll().resetUpScroll();
|
||||
});
|
||||
|
||||
function getData(page = 1, per_page = 10) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!pageReady.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let res = null;
|
||||
let activities = [];
|
||||
if (isActivitePage.value) {
|
||||
res = await queryAactivitiesList({ page, per_page });
|
||||
activities = res.data.activities.map(item => {
|
||||
item.start_at = dayjs(item.start_at).format('YYYY-MM-DD');
|
||||
item.end_at = dayjs(item.end_at).format('YYYY-MM-DD');
|
||||
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
res = await queryUserActivitiesList({ page, per_page });
|
||||
activities = res.data.activities.map(item => {
|
||||
const activity = item.activity;
|
||||
activity.has_gift = item.has_gift;
|
||||
|
||||
activity.start_at = dayjs(activity.start_at).format('YYYY-MM-DD');
|
||||
activity.end_at = dayjs(activity.end_at).format('YYYY-MM-DD');
|
||||
console.log(activity, 'activity')
|
||||
|
||||
return activity;
|
||||
});
|
||||
}
|
||||
|
||||
resolve(activities);
|
||||
});
|
||||
}
|
||||
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||
|
||||
const list = ref([]);
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' && getData(mescroll.num, mescroll.size).then(data => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data;
|
||||
}
|
||||
if (mescroll.num == 1) list.value = []; // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData); //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
|
||||
}).catch(() => {
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
};
|
||||
|
||||
onShareAppMessage((res) => {
|
||||
return {
|
||||
title: '活动列表',
|
||||
path: `/pages/activities/activities`
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-activates {
|
||||
padding: 16px 20px;
|
||||
|
||||
.mescroll-body-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.activate-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
.activate-cover {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.state-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.gift-tag {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
bottom: calc(38px + 8px);
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
background-color: #DC6F46;
|
||||
color: #fff;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.activate-info {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 6px;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
gap: 12px;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.time {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<view class="page-setting">
|
||||
<view class="setting-box">
|
||||
<view class="block-box bg-white rounded">
|
||||
<view class="flex text-primary items-center cell text-base">
|
||||
<text class="text">头像</text>
|
||||
<button class="menu-item-btn" openType="chooseAvatar" @chooseavatar="handleChooseAvatar">
|
||||
<image :src="form.avatar" />
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="flex text-primary items-center cell text-base">
|
||||
<view class="menu-item">
|
||||
<text class="text">昵称</text>
|
||||
</view>
|
||||
<input type="nickname" class="weui-input" :placeholder="form.nick_name" style="text-align:right;"
|
||||
@change="handleInputNickname" />
|
||||
<image class="icon" src="@/static/icons/arrow.svg" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button class="btn-save" @click="handleUpdateUserInfo">
|
||||
保存
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, getCurrentInstance } from 'vue';
|
||||
import useAuthUser from '@/utils/hooks/useAuthUser';
|
||||
import { submitUploadAvatar, submitUploadUserInfo } from '@/api/xinjiang_guess';
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
|
||||
const vm = getCurrentInstance();
|
||||
|
||||
const { login } = useAuthUser();
|
||||
|
||||
const form = ref({
|
||||
nick_name: '',
|
||||
avatar: '',
|
||||
});
|
||||
|
||||
function handleChooseAvatar(e) {
|
||||
console.log('handleChooseAvatar', e);
|
||||
form.value.avatar = e.detail.avatarUrl;
|
||||
}
|
||||
|
||||
function handleInputNickname(e) {
|
||||
console.log('handleInputNickname', e);
|
||||
if (!e.detail.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
form.value.nick_name = e.detail.value;
|
||||
}
|
||||
async function handleUpdateUserInfo() {
|
||||
if (form.value.avatar.includes('tmp')) {
|
||||
const uploadRes = await submitUploadAvatar({
|
||||
filePath: form.value.avatar,
|
||||
})
|
||||
|
||||
form.value.avatar = uploadRes.data.file;
|
||||
}
|
||||
|
||||
submitUploadUserInfo({
|
||||
avatar: form.value.avatar,
|
||||
nick_name: form.value.nick_name,
|
||||
}).then(() => {
|
||||
uni.$u.toast('更新成功');
|
||||
login(true).then(function () {
|
||||
loadUserInfo();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadUserInfo() {
|
||||
const { user } = useAuthUser();
|
||||
|
||||
if (user) {
|
||||
form.value.nick_name = user.nick_name;
|
||||
form.value.avatar = user.avatar;
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((query) => {
|
||||
loadUserInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.cell {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.page-setting {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
min-height: 100vh;
|
||||
gap: 12px;
|
||||
|
||||
.setting-box {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu-item-btn {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
image {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item,
|
||||
.u-button {
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
font-size: 16px !important;
|
||||
flex: 1;
|
||||
justify-content: space-between !important;
|
||||
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.extra {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.u-button .extra {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.btn-save {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
background-color: #1b2f85;
|
||||
color: #fff;
|
||||
width: calc(100vw - 24px);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
|
||||
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue"
|
||||
}
|
||||
},
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/activities/activities",
|
||||
"style": {
|
||||
"navigationBarTitleText": "活动"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/news/news",
|
||||
"style": {
|
||||
"navigationBarTitleText": "资讯"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/charts/charts",
|
||||
"style": {
|
||||
"navigationBarTitleText": "排行榜"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/webview/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "packages",
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/setting/setting",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/activeDetail/activeDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "活动详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/quizRecord/quizRecord",
|
||||
"style": {
|
||||
"navigationBarTitleText": "竞猜记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/news/newDetail/newDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "资讯详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/award/award",
|
||||
"style": {
|
||||
"navigationBarTitleText": "奖品记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/awardDetail/awardDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "奖品记录详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/about/about",
|
||||
"style": {
|
||||
"navigationBarTitleText": "关于我们"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"backgroundColor": "#f3f3f3",
|
||||
"navigationBarBackgroundColor": "#1b2f85"
|
||||
},
|
||||
"tabBar": {
|
||||
"selectedColor": "#182c5f",
|
||||
"iconWidth": "16px",
|
||||
"height": "70px",
|
||||
"list": [
|
||||
{
|
||||
"text": "首页",
|
||||
"pagePath": "pages/index/index",
|
||||
"iconPath": "static/icons/home.png",
|
||||
"selectedIconPath": "static/icons/home-1.png"
|
||||
},
|
||||
{
|
||||
"text": "竞猜",
|
||||
"pagePath": "pages/activities/activities",
|
||||
"iconPath": "static/icons/star.png",
|
||||
"selectedIconPath": "static/icons/star-1.png"
|
||||
},
|
||||
{
|
||||
"text": "排行榜",
|
||||
"pagePath": "pages/charts/charts",
|
||||
"iconPath": "static/icons/charts.png",
|
||||
"selectedIconPath": "static/icons/charts-1.png"
|
||||
},
|
||||
{
|
||||
"text": "资讯",
|
||||
"pagePath": "pages/news/news",
|
||||
"iconPath": "static/icons/earth.png",
|
||||
"selectedIconPath": "static/icons/earth-1.png"
|
||||
},
|
||||
{
|
||||
"text": "我的",
|
||||
"pagePath": "pages/my/index",
|
||||
"iconPath": "static/icons/my.png",
|
||||
"selectedIconPath": "static/icons/my-1.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
<template>
|
||||
<view class="page-activates">
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :down="{
|
||||
auto: false,
|
||||
}" :up="{
|
||||
empty: {
|
||||
use: true,
|
||||
}
|
||||
}">
|
||||
<view class="activate-box" v-for="(item, index) in list" :key="index"
|
||||
@click="$goToPage({ url: 'packages/pages/activeDetail/activeDetail', params: { id: item.id } })">
|
||||
<image class="activate-cover" mode="aspectFill" :src="item.cover" />
|
||||
<image class="state-image" mode="aspectFit" src="/static/images/active-processing.svg"
|
||||
v-if="item.state === 1" />
|
||||
<image class="state-image" mode="aspectFit" src="/static/images/active-finished.svg" v-if="item.state === 2" />
|
||||
<view class="gift-tag" v-if="item.has_gift">已获奖</view>
|
||||
|
||||
<view class="activate-info">
|
||||
<view class="title">{{ item.name }}</view>
|
||||
<view class="time">
|
||||
<view>{{ item.start_at }}</view>
|
||||
<view>至</view>
|
||||
<view>{{ item.end_at }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { queryAactivitiesList, queryUserActivitiesList } from '@/api/xinjiang_guess.js'
|
||||
import dayjs from 'dayjs';
|
||||
import { ref } from "vue";
|
||||
|
||||
const isActivitePage = ref(false);
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
if (isActivitePage) {
|
||||
isActivitePage.value = true;
|
||||
} else {
|
||||
isActivitePage.value = false;
|
||||
}
|
||||
|
||||
const pageReady = ref(false);
|
||||
|
||||
onLoad((query) => {
|
||||
console.log(query);
|
||||
|
||||
switch (query.source) {
|
||||
default:
|
||||
isActivitePage.value = true;
|
||||
break;
|
||||
case 'mine':
|
||||
isActivitePage.value = false;
|
||||
break;
|
||||
}
|
||||
pageReady.value = true;
|
||||
getMescroll().resetUpScroll();
|
||||
});
|
||||
|
||||
function getData(page = 1, per_page = 10) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!pageReady.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let res = null;
|
||||
let activities = [];
|
||||
if (isActivitePage.value) {
|
||||
res = await queryAactivitiesList({ page, per_page });
|
||||
activities = res.data.activities.map(item => {
|
||||
item.start_at = dayjs(item.start_at).format('YYYY-MM-DD');
|
||||
item.end_at = dayjs(item.end_at).format('YYYY-MM-DD');
|
||||
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
res = await queryUserActivitiesList({ page, per_page });
|
||||
activities = res.data.activities.map(item => {
|
||||
const activity = item.activity;
|
||||
activity.has_gift = item.has_gift;
|
||||
|
||||
activity.start_at = dayjs(activity.start_at).format('YYYY-MM-DD');
|
||||
activity.end_at = dayjs(activity.end_at).format('YYYY-MM-DD');
|
||||
console.log(activity, 'activity')
|
||||
|
||||
return activity;
|
||||
});
|
||||
}
|
||||
|
||||
resolve(activities);
|
||||
});
|
||||
}
|
||||
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||
|
||||
const list = ref([]);
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' && getData(mescroll.num, mescroll.size).then(data => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data;
|
||||
}
|
||||
if (mescroll.num == 1) list.value = []; // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData); //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
|
||||
}).catch(() => {
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
};
|
||||
|
||||
onShareAppMessage((res) => {
|
||||
return {
|
||||
title: '活动列表',
|
||||
path: `/pages/activities/activities`
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page-activates {
|
||||
padding: 16px 20px;
|
||||
|
||||
.mescroll-body-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.activate-box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
|
||||
.activate-cover {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.state-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.gift-tag {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
bottom: calc(38px + 8px);
|
||||
padding: 2px 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
background-color: #DC6F46;
|
||||
color: #fff;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.activate-info {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 6px;
|
||||
background: #fff;
|
||||
flex-shrink: 0;
|
||||
gap: 12px;
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.time {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<template>
|
||||
<view class="mask">
|
||||
<view class="content bg-white">
|
||||
<view class="flex items-center head">
|
||||
<view class="text-xs">活动规则</view>
|
||||
<view class="iconbar" @click="$emit('close')">
|
||||
<image class="icon" src="../../static//images/error.png" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-16 text-xs text-4e text-center ">
|
||||
{{ props.rules }}
|
||||
</view>
|
||||
<view class="flex items-center">
|
||||
<button class="btn" @click="$emit('close')">我知道了</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
rules: String,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close"]);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mask {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.content {
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 59%;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
.head {
|
||||
position: relative;
|
||||
justify-content: center;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
.iconbar {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
.icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
width: 60px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
padding: 0px !important;
|
||||
margin: 0 auto;
|
||||
font-size: 12px;
|
||||
border-radius: 4px !important;
|
||||
box-shadow: 1px 0.4px 1px #888;
|
||||
background-color: #182c5f;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,713 @@
|
|||
<template>
|
||||
<view class="home-page">
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :up="{
|
||||
empty: {
|
||||
use: false,
|
||||
}
|
||||
}">
|
||||
<view class="home-banner" v-if="homeBannerList.length">
|
||||
<up-swiper class="bg" :radius="0" height="200" :list="homeBannerList"
|
||||
:displayMultipleItems="displayMultipleItems" keyName="url" @click="clickHomeBanner"></up-swiper>
|
||||
</view>
|
||||
<view class="home-content" v-if="gameInfo || articleList.length">
|
||||
<image class="bg" mode="widthFix" :src="`${config.baseUrl}/images/mini-bg.jpg`"></image>
|
||||
|
||||
<view class="today-guess-box" v-if="gameInfo">
|
||||
<view class="title">今日竞猜</view>
|
||||
<view class="vs-box">
|
||||
<view class="left">
|
||||
<up-avatar class="item-box" size="48" mode="aspectFit"
|
||||
:src="gameInfo.home_logo"></up-avatar>
|
||||
<view class="item-text">{{ gameInfo.home_field }}</view>
|
||||
</view>
|
||||
<view class="middle">
|
||||
<view class="item-box">vs</view>
|
||||
<view class="item-text">{{ gameInfo.little_game_at }}</view>
|
||||
</view>
|
||||
<view class="right">
|
||||
<up-avatar class="item-box" size="48" mode="aspectFit"
|
||||
:src="gameInfo.away_logo"></up-avatar>
|
||||
<view class="item-text">{{ gameInfo.away }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="operation-box">
|
||||
<up-button class="guess-btn" :disabled="false" shape="circle" @click="showGuessModal(gameInfo)"
|
||||
:customStyle="{ margin: 0, width: '132px', backgroundColor: '#1D2B5C', color: '#fff', opacity: 1 }"
|
||||
v-if="!gameInfo.game_at_comparison_now && !gameInfo.has_guess">立即竞猜</up-button>
|
||||
|
||||
<up-button class="guess-btn disabled" :disabled="false" shape="circle"
|
||||
@click="showGuessModal(gameInfo)"
|
||||
:customStyle="{ margin: 0, width: '132px', backgroundColor: '#1D2B5C', color: '#fff', opacity: 0.7 }"
|
||||
v-if="gameInfo.has_guess">已竞猜</up-button>
|
||||
|
||||
<up-button class="guess-btn disabled" :disabled="true" shape="circle"
|
||||
@click="showGuessModal(gameInfo)"
|
||||
:customStyle="{ margin: 0, width: '132px', backgroundColor: '#1D2B5C', color: '#fff', opacity: 0.7 }"
|
||||
v-if="gameInfo.game_at_comparison_now && !gameInfo.has_guess">已结束</up-button>
|
||||
|
||||
<up-button class="more-btn" :disabled="false" shape="circle" @click="goToActivateDetailPage"
|
||||
:customStyle="{ margin: 0, width: '75px', backgroundColor: '#f0f0f0', color: '#000', opacity: 1 }">更多</up-button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="news-box" v-if="articleList.length">
|
||||
<view class="news-title-box">
|
||||
<text class="title">体彩资讯</text>
|
||||
<text class="more" @click="$goToPage('pages/news/news', true)">查看更多</text>
|
||||
</view>
|
||||
|
||||
<view v-for="(item, index) in articleList" :key="index"
|
||||
@click="$goToPage({ url: 'packages/pages/news/newDetail/newDetail', params: { id: item.id } })">
|
||||
<view class="news-image-box" :class="{ 'last': index === articleList.length - 1 }"
|
||||
v-if="item.cover">
|
||||
<image class="news-image" :src="item.cover"></image>
|
||||
<view class="news-info">
|
||||
<view class="news-info-title">{{ item.title }}</view>
|
||||
<view class="news-info-publish_time">{{ item.published_at }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="news-content-box" :class="{ 'last': index === articleList.length - 1 }" v-else>
|
||||
<view class="news-info">
|
||||
<view class="news-info-title">{{ item.title }}</view>
|
||||
<view class="news-info-publish_time">{{ item.published_at }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="guess-model" v-if="gameInfo">
|
||||
<up-modal :show="showGuessModalVisible" :width="335" :closeOnClickOverlay="true"
|
||||
:showConfirmButton="false" :showCancelButton="false" @close="hideGuessModal">
|
||||
<view class="slot-content">
|
||||
<view class="guess-title">
|
||||
<view>{{ gameInfo.home_field }}</view>
|
||||
<view>VS</view>
|
||||
<view>{{ gameInfo.away }}</view>
|
||||
</view>
|
||||
|
||||
<view class="guess-table">
|
||||
<view class="row herder-title">
|
||||
<view class="table-td col-12">单</view>
|
||||
</view>
|
||||
<view class="table-tr row row-3">
|
||||
<view class="row-title table-td row-3 col-10">胜</view>
|
||||
<view class="row-content">
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '1:0' }"
|
||||
@click="userGuessChange('1:0')">1:0</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '2:0' }"
|
||||
@click="userGuessChange('2:0')">2:0</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '2:1' }"
|
||||
@click="userGuessChange('2:1')">2:1</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '3:0' }"
|
||||
@click="userGuessChange('3:0')">3:0</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '3:1' }"
|
||||
@click="userGuessChange('3:1')">3:1</view>
|
||||
</view>
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '3:2' }"
|
||||
@click="userGuessChange('3:2')">3:2</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '4:0' }"
|
||||
@click="userGuessChange('4:0')">4:0</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '4:1' }"
|
||||
@click="userGuessChange('4:1')">4:1</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '4:2' }"
|
||||
@click="userGuessChange('4:2')">4:2</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '5:0' }"
|
||||
@click="userGuessChange('5:0')">5:0</view>
|
||||
</view>
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '5:1' }"
|
||||
@click="userGuessChange('5:1')">5:1</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '5:2' }"
|
||||
@click="userGuessChange('5:2')">5:2</view>
|
||||
<view class="table-td col-6" :class="{ 'active': userGuess === '胜其他' }"
|
||||
@click="userGuessChange('胜其他')">胜其他</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="table-tr row row-1">
|
||||
<view class="row-title table-td row-1 col-10">平</view>
|
||||
<view class="row-content">
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '0:0' }"
|
||||
@click="userGuessChange('0:0')">0:0</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '1:1' }"
|
||||
@click="userGuessChange('1:1')">1:1</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '2:2' }"
|
||||
@click="userGuessChange('2:2')">2:2</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '3:3' }"
|
||||
@click="userGuessChange('3:3')">3:3</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '平其他' }"
|
||||
@click="userGuessChange('平其他')">平其他</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="table-tr row row-3">
|
||||
<view class="row-title table-td row-3 col-10">负</view>
|
||||
<view class="row-content">
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '0:1' }"
|
||||
@click="userGuessChange('0:1')">0:1</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '0:2' }"
|
||||
@click="userGuessChange('0:2')">0:2</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '0:3' }"
|
||||
@click="userGuessChange('0:3')">0:3</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '0:4' }"
|
||||
@click="userGuessChange('0:4')">0:4</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '0:5' }"
|
||||
@click="userGuessChange('0:5')">0:5</view>
|
||||
</view>
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '1:2' }"
|
||||
@click="userGuessChange('1:2')">1:2</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '1:3' }"
|
||||
@click="userGuessChange('1:3')">1:3</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '1:4' }"
|
||||
@click="userGuessChange('1:4')">1:4</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '1:5' }"
|
||||
@click="userGuessChange('1:5')">1:5</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '2:3' }"
|
||||
@click="userGuessChange('2:3')">2:3</view>
|
||||
</view>
|
||||
<view class="row-1 col-10">
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '2:4' }"
|
||||
@click="userGuessChange('2:4')">2:4</view>
|
||||
<view class="table-td col-2" :class="{ 'active': userGuess === '2:5' }"
|
||||
@click="userGuessChange('2:5')">2:5</view>
|
||||
<view class="table-td col-6" :class="{ 'active': userGuess === '负其他' }"
|
||||
@click="userGuessChange('负其他')">负其他</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="guess-btns" v-if="!readonly">
|
||||
<up-button class="more-btn"
|
||||
:customStyle="{ margin: 0, width: '120px', backgroundColor: '#D9D9D9', color: '#000', }"
|
||||
shape="circle" text="取消" @click="hideGuessModal"></up-button>
|
||||
|
||||
<up-button class="more-btn"
|
||||
:customStyle="{ margin: 0, width: '120px', backgroundColor: '#5fb358', color: '#fff', }"
|
||||
shape="circle" text="确定" @click="submitGuessResult"></up-button>
|
||||
</view>
|
||||
</view>
|
||||
</up-modal>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, getCurrentInstance } from 'vue';
|
||||
import config from '@/common/config'
|
||||
import { queryAds, queryLatestgame, queryRecommendArticles, submitGuess } from '@/api/xinjiang_guess';
|
||||
import useAuthUser from '@/utils/hooks/useAuthUser';
|
||||
import jumpFun from '@/utils/jump.js'
|
||||
const vm = getCurrentInstance();
|
||||
|
||||
const loading = ref(false);
|
||||
const homeBannerLoading = ref(false);
|
||||
const homeBannerInfo = ref(null);
|
||||
const homeBannerList = ref([]);
|
||||
const displayMultipleItems = ref(0);
|
||||
|
||||
const showGuessModalVisible = ref(false);
|
||||
const gameInfoLoading = ref(false);
|
||||
const gameInfo = ref(null);
|
||||
const readonly = ref(false);
|
||||
const userGuess = ref('0:0');
|
||||
const submitGuessLoading = ref(false);
|
||||
|
||||
const articleListLoading = ref(false);
|
||||
const articleList = ref([]);
|
||||
|
||||
function clickHomeBanner(index) {
|
||||
// if (!homeBannerList.value.length) {
|
||||
// return;
|
||||
// }
|
||||
const item = homeBannerList.value[index]
|
||||
jumpFun(item)
|
||||
}
|
||||
|
||||
function userGuessChange(score) {
|
||||
if (readonly.value) {
|
||||
return;
|
||||
}
|
||||
userGuess.value = score;
|
||||
}
|
||||
function showGuessModal(item) {
|
||||
const { user } = useAuthUser();
|
||||
if (user.is_need_bind_phone) {
|
||||
vm.proxy.$goToPage('packages/pages/login/login?previous=index');
|
||||
return;
|
||||
}
|
||||
|
||||
gameInfo.value = item;
|
||||
|
||||
if (gameInfo.value.has_guess) {
|
||||
readonly.value = true;
|
||||
}
|
||||
if (gameInfo.value.game_at_comparison_now) {
|
||||
readonly.value = true;
|
||||
}
|
||||
|
||||
if (readonly.value) {
|
||||
userGuess.value = item.has_guess;
|
||||
} else {
|
||||
userGuess.value = '0:0';
|
||||
}
|
||||
|
||||
showGuessModalVisible.value = true;
|
||||
}
|
||||
function hideGuessModal() {
|
||||
showGuessModalVisible.value = false;
|
||||
setTimeout(() => {
|
||||
userGuess.value = '0:0';
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function goToActivateDetailPage() {
|
||||
vm.proxy.$goToPage({
|
||||
url: 'packages/pages/activeDetail/activeDetail',
|
||||
params: {
|
||||
id: gameInfo.value.activity_id,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function getHomeBanner() {
|
||||
try {
|
||||
homeBannerLoading.value = true;
|
||||
const resp = await queryAds({
|
||||
address: "index-top",
|
||||
});
|
||||
homeBannerInfo.value = resp.data;
|
||||
|
||||
homeBannerList.value = resp.data?.ads.map(item => {
|
||||
return {
|
||||
url: item.resource,
|
||||
title: "",
|
||||
poster: "",
|
||||
jump_type: item.jump_type,
|
||||
jump_config: item.jump_config,
|
||||
}
|
||||
}) || [];
|
||||
|
||||
displayMultipleItems.value = 1;
|
||||
if (homeBannerList.value.length > 3) {
|
||||
displayMultipleItems.value = 3;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
homeBannerLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getLatestGuess() {
|
||||
try {
|
||||
gameInfoLoading.value = true;
|
||||
const resp = await queryLatestgame()
|
||||
gameInfo.value = resp.data;
|
||||
if (gameInfo.value && gameInfo.value.has_guess) {
|
||||
userGuess.value = gameInfo.value.has_guess;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
gameInfoLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getRecommendArticles(params) {
|
||||
try {
|
||||
articleListLoading.value = true;
|
||||
const resp = await queryRecommendArticles(params)
|
||||
articleList.value = resp.data?.articles || [];
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
articleListLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function submitGuessResult() {
|
||||
try {
|
||||
uni.showLoading({
|
||||
title: "加载中..."
|
||||
});
|
||||
|
||||
const params = {
|
||||
game: gameInfo.value.id,
|
||||
score: userGuess.value,
|
||||
};
|
||||
submitGuessLoading.value = true;
|
||||
const res = await submitGuess(params, { custom: { catch: true } });
|
||||
|
||||
console.log('submitGuess', res);
|
||||
|
||||
uni.showToast({
|
||||
title: res.message,
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
getLatestGuess();
|
||||
setTimeout(hideGuessModal, 0);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
submitGuessLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getData(page = 1, per_page = 10) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
loading.value = true;
|
||||
setTimeout(async () => {
|
||||
await getHomeBanner();
|
||||
await getLatestGuess();
|
||||
await getRecommendArticles();
|
||||
resolve();
|
||||
}, 1500);
|
||||
} catch (err) {
|
||||
console.log('getData index', err);
|
||||
reject();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||
|
||||
const list = ref([]);
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' && getData(mescroll.num, mescroll.size).then(data => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data;
|
||||
}
|
||||
if (mescroll.num == 1) list.value = []; // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData); //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.home-banner {
|
||||
height: 200px;
|
||||
|
||||
image.bg {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.home-content {
|
||||
position: relative;
|
||||
padding: 20px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
|
||||
background-color: #1b2f85;
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.today-guess-box {
|
||||
padding: 12px;
|
||||
width: calc(100% - 32px);
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
z-index: 999;
|
||||
|
||||
.title {
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vs-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.item-box {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
text-align: center;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
margin-top: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.left,
|
||||
.middle,
|
||||
.right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.operation-box {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
justify-content: center;
|
||||
|
||||
.guess-btn {
|
||||
margin: 0;
|
||||
width: 132px;
|
||||
background-color: #1D2B5C;
|
||||
color: #fff;
|
||||
border-radius: 50px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.guess-btn.disabled {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.more-btn {
|
||||
margin: 0;
|
||||
width: 75px;
|
||||
background-color: #f0f0f0;
|
||||
color: #000;
|
||||
border-radius: 50px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.news-box {
|
||||
padding: 12px;
|
||||
width: calc(100% - 32px);
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
z-index: 999;
|
||||
|
||||
.news-title-box {
|
||||
padding-left: 12px;
|
||||
border-left: 4px solid #D8524C;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.more {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.news-image-box,
|
||||
.news-content-box {
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.news-image-box {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
.news-image {
|
||||
flex-shrink: 0;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.news-info {
|
||||
height: 100%;
|
||||
padding: 8px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: flex-start;
|
||||
gap: 12px;
|
||||
|
||||
&-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
&-publish_time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.last {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.u-modal {
|
||||
width: calc(100% - 16px * 2);
|
||||
|
||||
.u-modal__content {
|
||||
padding: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.guess-model {
|
||||
.slot-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.guess-title {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 58px;
|
||||
}
|
||||
|
||||
.guess-table {
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
|
||||
.table-td {
|
||||
border: 1px solid #bbb;
|
||||
width: 48px !important;
|
||||
}
|
||||
|
||||
.table-td.active {
|
||||
background-color: #1D2B5C;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.row-1 {
|
||||
height: calc(30px * 1 - 2px) !important;
|
||||
line-height: calc(30px * 1 - 2px) !important;
|
||||
}
|
||||
|
||||
.row-2 {
|
||||
height: calc(30px * 2 - 2px) !important;
|
||||
line-height: calc(30px * 2 - 2px) !important;
|
||||
}
|
||||
|
||||
.row-3 {
|
||||
height: calc(30px * 3 - 8px) !important;
|
||||
line-height: calc(30px * 3 - 8px) !important;
|
||||
}
|
||||
|
||||
.row {
|
||||
width: 300px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
text-align: center;
|
||||
|
||||
.col-1 {
|
||||
width: calc(292px / 12 * 1);
|
||||
}
|
||||
|
||||
.col-2 {
|
||||
width: calc(292px / 12 * 2);
|
||||
}
|
||||
|
||||
.col-10 {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-self: flex-start;
|
||||
flex-grow: 1;
|
||||
|
||||
.table-td {
|
||||
width: 47.7px !important;
|
||||
border: 1px solid #bbb;
|
||||
}
|
||||
|
||||
.col-6 {
|
||||
width: calc(47.7px * 3 + 4px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.col-12 {
|
||||
width: 292px;
|
||||
}
|
||||
}
|
||||
|
||||
.herder-title {
|
||||
background-color: #1D2B5C;
|
||||
color: #fff;
|
||||
|
||||
.table-td {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.row-title {
|
||||
background-color: #D9D9D9;
|
||||
width: 48px !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
.row-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: calc(300px - 48px - 3px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.guess-btns {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 300px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
<template>
|
||||
<view class="phone">
|
||||
<view class="phone-warp">
|
||||
<view class="text-sm">人工客服</view>
|
||||
<view style="margin-top: 10rpx">
|
||||
<up-text mode="phone" call text="400-9915-666"></up-text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<mescroll-body
|
||||
@init="mescrollInit"
|
||||
@down="downCallback"
|
||||
@up="upCallback"
|
||||
:up="{
|
||||
empty: {
|
||||
use: false,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<view class="mine-page">
|
||||
<view class="p-16">
|
||||
<view class="userinfo-box">
|
||||
<view class="userinfo" @click="handleClickUserInfo">
|
||||
<up-avatar
|
||||
class="avatar"
|
||||
size="48"
|
||||
mode="aspectFit"
|
||||
:src="`${
|
||||
(user && user?.avatar) || '/static/images/example-avatar1.png'
|
||||
}`"
|
||||
></up-avatar>
|
||||
<view v-if="user?.is_need_bind_phone === true"> 登陆/注册 </view>
|
||||
<div v-else>
|
||||
{{ user?.nick_name || '' }}
|
||||
</div>
|
||||
</view>
|
||||
<div @click="goToSetting" v-if="user">
|
||||
<image
|
||||
class="setting"
|
||||
mode="aspectFit"
|
||||
src="@/static/icons/setting.svg"
|
||||
/>
|
||||
</div>
|
||||
</view>
|
||||
<view v-for="(block, index) in menus" :key="index">
|
||||
<view class="block-box bg-white rounded">
|
||||
<view v-for="(item, index) in block" :key="index">
|
||||
<view
|
||||
class="flex text-primary items-center cell text-base"
|
||||
@click="goToMenuPage(item)"
|
||||
v-if="!item.openType"
|
||||
>
|
||||
<image class="icon mr-12" :src="item.icon" />
|
||||
<view class="menu-item" :openType="item.openType">
|
||||
<text class="text">{{ item.text }}</text>
|
||||
<text class="extra" v-if="item.extra">{{ item.extra }}</text>
|
||||
</view>
|
||||
<image class="icon" src="@/static/icons/arrow.svg" />
|
||||
</view>
|
||||
|
||||
<view
|
||||
class="flex text-primary items-center cell text-base"
|
||||
v-if="item.openType"
|
||||
>
|
||||
<image class="icon mr-12" :src="item.icon" />
|
||||
<up-button class="menu-item-btn" :openType="item.openType">
|
||||
<text class="text">{{ item.text }}</text>
|
||||
<text class="extra" v-if="item.extra">{{ item.extra }}</text>
|
||||
</up-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, getCurrentInstance } from 'vue'
|
||||
import useAuthUser from '@/utils/hooks/useAuthUser'
|
||||
|
||||
const vm = getCurrentInstance()
|
||||
const user = ref(null)
|
||||
|
||||
const menus = ref([
|
||||
[
|
||||
{
|
||||
icon: '/static/icons/record.svg',
|
||||
text: '竞猜记录',
|
||||
extra: '竞猜记录列表',
|
||||
url: '/packages/pages/quizRecord/quizRecord?source=mine',
|
||||
isTabbarPage: false,
|
||||
isNeedAuth: true,
|
||||
},
|
||||
{
|
||||
icon: '/static/icons/gift.svg',
|
||||
text: '奖品记录',
|
||||
extra: '奖品记录列表',
|
||||
url: '/packages/pages/award/award',
|
||||
isTabbarPage: false,
|
||||
isNeedAuth: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
icon: '/static/icons/customer-service.svg',
|
||||
text: '在线客服',
|
||||
extra: '客服在线时间 08:00~17:00',
|
||||
url: '',
|
||||
openType: 'contact',
|
||||
isTabbarPage: false,
|
||||
isNeedAuth: false,
|
||||
},
|
||||
{
|
||||
icon: '/static/icons/info.svg',
|
||||
text: '关于我们',
|
||||
url: '/packages/pages/about/about',
|
||||
isTabbarPage: false,
|
||||
isNeedAuth: false,
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
function handleClickUserInfo() {
|
||||
if (user.value && !user.value.is_need_bind_phone) {
|
||||
return
|
||||
}
|
||||
|
||||
vm.proxy.$goToPage('packages/pages/login/login?previous=my')
|
||||
}
|
||||
|
||||
function goToMenuPage(item) {
|
||||
console.log(item)
|
||||
|
||||
if (item?.isNeedAuth) {
|
||||
if (user.value && !user.value.is_need_bind_phone) {
|
||||
vm.proxy.$goToPage(item.url, item.isTabbarPage)
|
||||
return
|
||||
}
|
||||
vm.proxy.$goToPage(
|
||||
'packages/pages/login/login?previous=custom&url=' + item.url
|
||||
)
|
||||
} else {
|
||||
vm.proxy.$goToPage(item.url, item.isTabbarPage)
|
||||
}
|
||||
}
|
||||
|
||||
function goToSetting() {
|
||||
if (user.value && !user.value.is_need_bind_phone) {
|
||||
vm.proxy.$goToPage('packages/pages/setting/setting')
|
||||
return
|
||||
}
|
||||
|
||||
vm.proxy.$goToPage('packages/pages/login/login?previous=setting')
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
console.log('onShow')
|
||||
|
||||
const authUser = useAuthUser()
|
||||
user.value = authUser.user
|
||||
})
|
||||
|
||||
function getData() {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
|
||||
import {
|
||||
onShow,
|
||||
onLoad,
|
||||
onPullDownRefresh,
|
||||
onPageScroll,
|
||||
onReachBottom,
|
||||
onShareAppMessage,
|
||||
} from '@dcloudio/uni-app'
|
||||
import useMescroll from '@/uni_modules/mescroll-uni/hooks/useMescroll.js'
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(
|
||||
onPageScroll,
|
||||
onReachBottom
|
||||
)
|
||||
|
||||
const list = ref([])
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' &&
|
||||
getData(mescroll.num, mescroll.size)
|
||||
.then((data) => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data
|
||||
}
|
||||
if (mescroll.num == 1) list.value = [] // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData) //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length) // 请求成功, 结束加载
|
||||
})
|
||||
.catch(() => {
|
||||
mescroll.endErr() // 请求失败, 结束加载
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.phone {
|
||||
position: fixed;
|
||||
bottom: 50rpx;
|
||||
z-index: 9999;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
&-warp{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.mr-12 {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.cell {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.mine-page {
|
||||
.userinfo-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.setting {
|
||||
margin-right: 12px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-item,
|
||||
.u-button {
|
||||
border: none !important;
|
||||
padding: 0 !important;
|
||||
font-size: 16px !important;
|
||||
flex: 1;
|
||||
justify-content: space-between !important;
|
||||
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.extra {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.u-button .extra {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
<template>
|
||||
<mescroll-body @init="mescrollInit" @down="downCallback" @up="upCallback" :up="{
|
||||
empty: {
|
||||
use: true,
|
||||
}
|
||||
}">
|
||||
<view class="page-news">
|
||||
<up-sticky class="news-tab" bgColor="#fff">
|
||||
<up-tabs lineColor="#1d2b5c" :list="tablist" @click="changeTab"></up-tabs>
|
||||
</up-sticky>
|
||||
|
||||
<view class="card-box" v-if="list.length">
|
||||
<view v-for="(item, index) in list" :key="index"
|
||||
@click="$goToPage({ url: 'packages/pages/news/newDetail/newDetail', params: { id: item.id } })">
|
||||
<view class="news-image-box" :class="{ 'last': index === list.length - 1 }" v-if="item.cover">
|
||||
<image class="news-image" :src="item.cover"></image>
|
||||
<view class="news-info">
|
||||
<view class="news-info-title">{{ item.title }}</view>
|
||||
<view class="news-info-publish_time">{{ item.published_at }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="news-content-box" :class="{ 'last': index === list.length - 1 }" v-else>
|
||||
<view class="news-info">
|
||||
<view class="news-info-title">{{ item.title }}</view>
|
||||
<view class="news-info-publish_time">{{ item.published_at }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</mescroll-body>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { getCategories, getArticlesList } from '@/api/xinjiang_guess.js';
|
||||
|
||||
const tablist = ref([]);
|
||||
const params = ref({
|
||||
category_key: '',
|
||||
});
|
||||
|
||||
onLoad(async () => {
|
||||
const categoriesRes = await getCategories()
|
||||
tablist.value = categoriesRes.data.categories;
|
||||
params.value.category_key = tablist.value[0].key;
|
||||
getMescroll().resetUpScroll();
|
||||
});
|
||||
|
||||
function changeTab(val) {
|
||||
params.value.category_key = val.key;
|
||||
list.value = [];
|
||||
getMescroll().resetUpScroll();
|
||||
}
|
||||
|
||||
function getData(page = 1, per_page = 10) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (!params.value.category_key) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
getArticlesList({
|
||||
category_key: params.value.category_key,
|
||||
page,
|
||||
per_page
|
||||
}).then((res) => {
|
||||
resolve(res.data.articles);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
import { onShow, onLoad, onPullDownRefresh, onPageScroll, onReachBottom, onShareAppMessage } from "@dcloudio/uni-app";
|
||||
import useMescroll from "@/uni_modules/mescroll-uni/hooks/useMescroll.js";
|
||||
const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom)
|
||||
|
||||
const list = ref([]);
|
||||
const upCallback = (mescroll) => {
|
||||
typeof getData === 'function' && getData(mescroll.num, mescroll.size).then(data => {
|
||||
let curPageData = [] // 当前页数据
|
||||
if (Array.isArray(data)) {
|
||||
curPageData = data;
|
||||
}
|
||||
if (mescroll.num == 1) list.value = []; // 第一页需手动制空列表
|
||||
list.value = list.value.concat(curPageData); //追加新数据
|
||||
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
|
||||
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
|
||||
|
||||
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
|
||||
//mescroll.endByPage(curPageData.length, totalPage); //必传参数(当前页的数据个数, 总页数)
|
||||
|
||||
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
|
||||
//mescroll.endBySize(curPageData.length, totalSize); //必传参数(当前页的数据个数, 总数据量)
|
||||
|
||||
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
|
||||
//mescroll.endSuccess(curPageData.length, hasNext); //必传参数(当前页的数据个数, 是否有下一页true/false)
|
||||
|
||||
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据.
|
||||
mescroll.endSuccess(curPageData.length); // 请求成功, 结束加载
|
||||
}).catch(() => {
|
||||
mescroll.endErr(); // 请求失败, 结束加载
|
||||
})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.mt-8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.m-title {
|
||||
margin: 8px 0 10px;
|
||||
}
|
||||
|
||||
.page-news {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.u-sticky {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.card-box {
|
||||
padding: 12px;
|
||||
width: calc(100% - 32px - 24px);
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
|
||||
.news-title-box {
|
||||
padding-left: 12px;
|
||||
border-left: 4px solid #D8524C;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
|
||||
.more {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.news-image-box,
|
||||
.news-content-box {
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.news-image-box {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
|
||||
.news-image {
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
padding: 12px 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.news-info {
|
||||
height: 100%;
|
||||
padding: 8px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-self: flex-start;
|
||||
gap: 12px;
|
||||
|
||||
&-title {
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
&-publish_time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.last {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<view style="">
|
||||
<view style="width: 100vw;height:100vh;position: relative;">
|
||||
<l-signature v-model="signatureUrl" style="border:0px solid #999;" ref="signatureRef" penColor="black"
|
||||
landscape :boundingBox="false" useCanvas2d preferToDataURL type></l-signature>
|
||||
</view>
|
||||
<h1 style="position: absolute;right:5%;top:50%;transform: rotate(90deg) translate(-50%, -50%);">{{ langKey?.lang_signed_text || '签名' }}</h1>
|
||||
<view style="position: absolute;top: 90%;left:50%;transform: translate(-50%, -50%) rotate(90deg);">
|
||||
<button style="width:100px;" @click="onClick('clear')">{{ langKey?.lang_signed_text || '签名' }}</button>
|
||||
<button style="width:100px;" @click="onClick('undo')">{{ langKey?.lang_cancel_button_text || '撤销' }}</button>
|
||||
<button style="width:100px;" @click="onClick('save')">{{ langKey?.lang_save_button_text || '保存' }}</button>
|
||||
<button style="width:100px;" @click="onClick('openSmooth')" v-if="false">压感{{openSmooth?'开':'关'}}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import load_langkey from "@/utils/mixins/load_langkey";
|
||||
|
||||
import bus from 'vue3-eventbus'
|
||||
export default {
|
||||
mixins: [
|
||||
load_langkey,
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
openSmooth: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClick(type) {
|
||||
if (!this.$refs.signatureRef) {
|
||||
return
|
||||
}
|
||||
if (type == 'openSmooth') {
|
||||
this.openSmooth = !this.openSmooth
|
||||
return
|
||||
}
|
||||
if (type == 'save') {
|
||||
console.log(this.$refs.signatureRef)
|
||||
this.$refs.signatureRef.canvasToTempFilePath({
|
||||
success: (res) => {
|
||||
console.log('canvasToTempFilePath', res)
|
||||
// console.log('canvasToMaskPath', res)
|
||||
|
||||
uni.setStorageSync('sign_res', res)
|
||||
uni.navigateTo({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
this.$refs.signatureRef[type]()
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<view>
|
||||
<web-view
|
||||
v-if="url"
|
||||
:src="url"
|
||||
></web-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { ref } from 'vue'
|
||||
const url = ref(null)
|
||||
|
||||
onLoad((e) => {
|
||||
if (e.url) {
|
||||
// url.value = decodeURIComponent(e.url)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
export {};
|
||||
|
||||
declare module "vue" {
|
||||
type Hooks = App.AppInstance & Page.PageInstance;
|
||||
interface ComponentCustomOptions extends Hooks {}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715956684890" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20180" data-spm-anchor-id="a313x.search_index.0.i16.4bca3a81d69fiH" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M728.223744 520.22784a42.467328 42.467328 0 0 1-11.393024 20.503552L374.90688 882.65728c-16.662528 16.662528-43.677696 16.662528-60.340224 0s-16.662528-43.677696 0-60.340224L626.449408 510.43328 314.614784 198.598656c-16.662528-16.662528-16.662528-43.677696 0-60.340224 16.661504-16.662528 43.676672-16.662528 60.3392 0L716.879872 480.18432c10.860544 10.860544 14.642176 26.120192 11.343872 40.04352z" fill="#131212" p-id="20181"></path></svg>
|
||||
|
After Width: | Height: | Size: 838 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.5 6.2158V3.90625C6.5 3.1296 7.1296 2.5 7.90625 2.5H20.0938C20.8704 2.5 21.5 3.1296 21.5 3.90625V16.0938C21.5 16.8704 20.8704 17.5 20.0938 17.5H17.7582" stroke="#9D9DB6" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M16.0938 6.5H3.90625C3.1296 6.5 2.5 7.1296 2.5 7.90625V20.0938C2.5 20.8704 3.1296 21.5 3.90625 21.5H16.0938C16.8704 21.5 17.5 20.8704 17.5 20.0938V7.90625C17.5 7.1296 16.8704 6.5 16.0938 6.5Z" stroke="#9D9DB6" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 578 B |
|
|
@ -0,0 +1,5 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 16C20.2092 16 22 14.2092 22 12C22 9.79085 20.2092 8 18 8" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M6 8C3.79086 8 2 9.79085 2 12C2 14.2092 3.79086 16 6 16" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M6 16V15.75V14.5V12V8C6 4.68629 8.6863 2 12 2C15.3137 2 18 4.68629 18 8V16C18 19.3137 15.3137 22 12 22" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 556 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -0,0 +1,7 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.5 22V10H3.5V22H20.5Z" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 22V10" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M20.5 22H3.5" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M22 6H2V10H22V6Z" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M8 2L12 6L16 2" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 625 B |
|
After Width: | Height: | Size: 965 B |
|
After Width: | Height: | Size: 903 B |
|
|
@ -0,0 +1,6 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C14.7614 22 17.2614 20.8807 19.0711 19.0711C20.8807 17.2614 22 14.7614 22 12C22 9.2386 20.8807 6.7386 19.0711 4.92893C17.2614 3.11929 14.7614 2 12 2C9.2386 2 6.7386 3.11929 4.92893 4.92893C3.11929 6.7386 2 9.2386 2 12C2 14.7614 3.11929 17.2614 4.92893 19.0711C6.7386 20.8807 9.2386 22 12 22Z" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 5.5C12.6904 5.5 13.25 6.05965 13.25 6.75C13.25 7.44035 12.6904 8 12 8C11.3097 8 10.75 7.44035 10.75 6.75C10.75 6.05965 11.3097 5.5 12 5.5Z" fill="#9D9DB6"/>
|
||||
<path d="M12.25 17V10H11.75H11.25" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10.5 17H14" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 904 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1715956588038" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18007" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M949.2 246.9l0.8-0.8L700.4 0.5l-1.2 1.2V1H155.4c-46.3 0-84 37.7-84 84v854.9c0 46.3 37.7 84 84 84h711.2c46.3 0 84-37.7 84-84v-693h-1.4zM719.5 95l157.2 154.7H749.5c-16.5 0-30-13.5-30-30V95z m147.1 874.9H155.4c-16.5 0-30-13.5-30-30V85c0-16.5 13.5-30 30-30h510.1v164.8c0 46.3 37.7 84 84 84h147.2V940c-0.1 16.5-13.6 29.9-30.1 29.9z" p-id="18008" fill="#272626"></path><path d="M543.5 369.4c-88-18-140.8 17.8-169.5 50.9-30.3 35-39.9 74.2-40.3 75.9l52.5 12.5v0.1c0.1-0.3 7.5-29.5 29.8-54.5 28-31.4 67.3-42.1 116.8-32 27.7 5.7 56.3 29.9 69.4 58.9 8.2 18.1 14.2 46.3-3.8 77.4-5.1 8.8-32.2 24-50.1 34-39.5 22.1-80.4 45-81.2 82.2v44.4h54v-42.4c0.7-1.3 3.7-5.8 14.8-13.8 10.7-7.7 25-15.7 38.8-23.4 29.8-16.7 58-32.5 70.5-54.2 22.9-39.8 25-84.7 6.2-126.5-20.5-45.1-62.8-80.3-107.9-89.5zM466.8 749.3h54v53.8h-54z" p-id="18009" fill="#272626"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -0,0 +1,5 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.5 3H4.5C3.67158 3 3 3.67158 3 4.5V19.5C3 20.3285 3.67158 21 4.5 21H19.5C20.3285 21 21 20.3285 21 19.5V4.5C21 3.67158 20.3285 3 19.5 3Z" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M12 14.3125V12.3125C13.6568 12.3125 15 10.9693 15 9.3125C15 7.65565 13.6568 6.3125 12 6.3125C10.3432 6.3125 9 7.65565 9 9.3125" stroke="#9D9DB6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 18.8125C12.6904 18.8125 13.25 18.2529 13.25 17.5625C13.25 16.8722 12.6904 16.3125 12 16.3125C11.3097 16.3125 10.75 16.8722 10.75 17.5625C10.75 18.2529 11.3097 18.8125 12 18.8125Z" fill="#9D9DB6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 782 B |
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.1419 21.5857C7.46635 21.0868 5.9749 20.1607 4.79393 18.9335C5.2345 18.4114 5.5 17.7367 5.5 17.0001C5.5 15.3432 4.15685 14.0001 2.5 14.0001C2.39977 14.0001 2.3007 14.005 2.203 14.0146C2.0699 13.3639 2 12.6902 2 12.0001C2 10.9548 2.16039 9.9469 2.4579 8.99975C2.47191 8.99995 2.48594 9.00005 2.5 9.00005C4.15685 9.00005 5.5 7.6569 5.5 6.00005C5.5 5.5244 5.3893 5.07465 5.1923 4.67506C6.34875 3.59975 7.76025 2.79501 9.32605 2.36157C9.8222 3.3341 10.8333 4.00007 12 4.00007C13.1667 4.00007 14.1778 3.3341 14.674 2.36157C16.2398 2.79501 17.6512 3.59975 18.8077 4.67506C18.6107 5.07465 18.5 5.5244 18.5 6.00005C18.5 7.6569 19.8432 9.00005 21.5 9.00005C21.5141 9.00005 21.5281 8.99995 21.5421 8.99975C21.8396 9.9469 22 10.9548 22 12.0001C22 12.6902 21.9301 13.3639 21.797 14.0146C21.6993 14.005 21.6002 14.0001 21.5 14.0001C19.8432 14.0001 18.5 15.3432 18.5 17.0001C18.5 17.7367 18.7655 18.4114 19.2061 18.9335C18.0251 20.1607 16.5336 21.0868 14.8581 21.5857C14.4714 20.376 13.338 19.5001 12 19.5001C10.662 19.5001 9.5286 20.376 9.1419 21.5857Z" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M12 15.5C13.933 15.5 15.5 13.933 15.5 12C15.5 10.067 13.933 8.5 12 8.5C10.067 8.5 8.5 10.067 8.5 12C8.5 13.933 10.067 15.5 12 15.5Z" stroke="#9D9DB6" stroke-width="2" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<mask id="mask0_29_3081" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="50" height="50">
|
||||
<rect width="50" height="50" fill="url(#pattern0_29_3081)"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_29_3081)">
|
||||
<rect x="12.4351" y="-14" width="73.2517" height="19" transform="rotate(45 12.4351 -14)" fill="#605E5E"/>
|
||||
<path d="M29.4698 15.8872L25.9173 12.3347L24.2485 14.0035C23.9996 14.2524 23.9996 14.5126 24.2598 14.7728L27.0996 17.6126C27.2353 17.7483 27.3824 17.8275 27.5351 17.8445C27.7501 17.8558 28.1857 17.5673 28.8419 16.979L29.1134 17.4994C28.3554 18.1443 27.8406 18.4668 27.5578 18.4781C27.3145 18.4724 27.0656 18.348 26.8167 18.1217L23.7507 15.0557C23.2925 14.5975 23.3038 14.1336 23.7677 13.6697L26.7375 10.6999L27.1448 11.1072L26.3076 11.9444L29.4472 15.084L30.9236 13.6075L27.1505 9.83439L27.5465 9.43841L31.7325 13.6245L29.4698 15.8872ZM30.9519 20.3561L30.5672 20.7408C29.7809 20.3731 28.9607 19.8923 28.0895 19.2927L28.4346 18.8458C29.3284 19.4906 30.1656 19.9884 30.9519 20.3561ZM33.9783 15.2367L34.2102 15.7628C33.1863 16.2097 32.3039 16.5038 31.5685 16.6509C31.8683 16.8828 32.1738 17.1091 32.4905 17.3354C32.8017 17.2392 33.1241 17.143 33.4522 17.0412L33.6785 17.5277C32.2077 17.9689 31.099 18.2178 30.3466 18.2801C30.8614 18.6251 31.3988 18.9363 31.9588 19.2135L31.5968 19.5755C30.7765 19.1739 30.0468 18.727 29.4076 18.2348L29.6678 17.7596C29.7753 17.7992 29.8771 17.8219 29.9732 17.8275C30.4088 17.8219 31.048 17.7144 31.8966 17.4994C31.5232 17.2279 31.1555 16.9507 30.7822 16.6679L31.0537 16.1927C31.1442 16.2266 31.2517 16.2323 31.3761 16.2097C32.2134 16.006 33.0789 15.6836 33.9783 15.2367ZM34.2385 16.9337L35.5905 18.2857L36.275 17.6013L36.6879 18.0142L36.0035 18.6987L37.3498 20.045L36.9538 20.441L35.6075 19.0947L34.7703 19.9319L35.9525 21.1142L35.5566 21.5101L32.796 18.7496L33.192 18.3536L34.3573 19.5189L35.1945 18.6817L33.8425 17.3297L34.2385 16.9337ZM34.8268 21.9118L32.5528 24.1858L32.1568 23.7899L32.4283 23.5183L30.8105 21.9005L30.5389 22.172L30.1373 21.7704L32.4113 19.4963L34.8268 21.9118ZM31.1951 21.5158L32.813 23.1337L34.0462 21.9005L32.4283 20.2826L31.1951 21.5158ZM37.8702 20.3279L40.082 22.5397L40.6477 21.974L41.0663 22.3926L40.5006 22.9583L42.7012 25.1588L42.3108 25.5491L40.1103 23.3486L39.556 23.903L41.3379 25.6849L39.737 27.2858L38.3001 25.8489C38.1304 26.8332 38.3114 28.0325 38.8206 29.4467L38.1927 29.5202C37.7514 27.959 37.6779 26.6296 37.972 25.5208L37.9551 25.5039L35.9016 27.5573L35.483 27.1387L37.5365 25.0853L37.5195 25.0683C36.3202 25.4077 34.9739 25.3285 33.4748 24.8251L33.6106 24.2141C34.9456 24.7572 36.1392 24.9325 37.1857 24.7345L35.7659 23.3147L37.3668 21.7138L39.1373 23.4844L39.6917 22.93L37.4799 20.7182L37.8702 20.3279ZM39.703 26.5051L40.5459 25.6623L39.1713 24.2877L38.3284 25.1305L39.703 26.5051ZM37.9098 24.7119L38.7527 23.869L37.3894 22.5057L36.5465 23.3486L37.9098 24.7119Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<pattern id="pattern0_29_3081" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_29_3081" transform="scale(0.00390625)"/>
|
||||
</pattern>
|
||||
<image id="image0_29_3081" width="256" height="256" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAAAXNSR0IArs4c6QAACixJREFUeF7t3TFSJEAMQ9HhBNz/jESkJLuH+EGXym9zirKxvmUx9H79/f39+4R/v7+/4as/n+/v7/T1vr/+lwG6Pn9fAABARUAAvA1gAOBAiv4/AAAAaYCuWzD1c2BFQBXAHAAHUOaPAxjPwAAAAAAgdKBu4NcOEAAAIIz/hwPgALZDkNcE9v1lAIXA1YFwABxAmT8OgAPgAIqCOAAOoMwPBzBOYAAAAAAIHagEJEACDOM3fwLJAGQAZf7nBXB9AQAAAABA6MC6AwUAAAjj73MAACCESwK6bkHV/zaD+fr5+UnvAfgBvv0B6r/+lw0EABxMmR8PuoyfkAAAAAAQOrDuwAAAAML4e9INAMYt0HqKuz6A+v/2o/QcAAfAAYQOrAMYAAAgjL8TAACcAElALPBbC3y9/xwAB5AAtr4BAcAHgQggdAAAtj+IxAFwAEH+MoB1AAIAAABA6AAACAHD+Phruus3+Ov6OQAOIAFsfQO+FuDr7w8AAAAAoQPrAAQAAAjjLwScB4D/Hnz71zivLaTvv/1BJk+CCTGTAwAAAEgDtG6hCGBbANfnjwPgABLAAXAbgAAAAAAQOrAOQAAAgDD+PsgEAH6NlgR0/QZV/9vfQnEAHEAC2PoGvA4gAAAAAAgdWAcgAABAGH8ZAADIAJKArltQ9csAkoDWCUwAbwVwvf9OACcAAIcOrC8gAACAMP4yAACQASQBXbeg6n97AnEAHEAC2PoGvA4gD4JwMAkA1wW0Xj8AAAAAhA4AAAsdxkeI5oR4++fEHAAHkAC2vgGvAwgAAAAAQgfWAQgAABDG36vAACADSAK6bkHVLwNIAlonMAG8FcD1/jsBnAAAHDqwvoAAAADC+MsAAEAGkAR03YKq/+0JxAFwAAlg6xvwOoAAAAAAIHRgHYAAAABh/GUAACADSAK6bkHVLwNIAlonMAG8FcD1/nsQhINJAL4uoPX6AQAAACB0AACEaGF8hGhOOG8CJgGtE5gA3grgev+dAE4AAA4dWF9AAAAAYfw9aQYAMoAkoOsWVP1vTyAOgANIAFvfgNcBBAAAAAChA+sABAAACOMvAwAAGUAS0HULqn4ZQBLQOoEJ4K0ArvffCeAEAODQgfUFBAAAEMZfBgAAMoAkoOsWVP1vTyAOgANIAFvfgNcB5EkwDiYB4LqA1usHAAAAgNABAGChw/gI0ZwQb59E4wA4gASw9Q14HUAAAAAAEDqwDkAAAIAw/p40AwAZQBLQdQuqfhlAEtA6gQngrQCu998J4AQA4NCB9QUEAAAQxl8GAAAygCSg6xZU/W9PIA6AA0gAW9+A1wEEAAAAAKED6wAEAAAI4y8DAAAZQBLQdQuqfhlAEtA6gQngrQCu99+DIBxMAvB1Aa3XDwAAAAChAwAgRAvjI0RzwnkTMAloncAE8FYA1/vvBHACAHDowPoCAgAACOPvSTMAkAEkAV23oOp/ewJxABxAAtj6BrwOIAAAAAAIHVgHIAAAQBh/GQAAyACSgK5bUPXLAJKA1glMAG8FcL3/TgAnAACHDqwvIAAAgDD+MgAAkAEkAV23oOp/ewJxABxAAtj6BrwOIE+CcTAJANcFtF4/AAAAAIQOAAALHcZHiOaEePskGgfAASSArW/A6wACAAAAgNCBdQACAACE8fekGQDIAJKArltQ9csAkoDWCUwAbwVwvf9OACcAAIcOrC8gAACAMP4yAACQASQBXbeg6n97AnEAHEAC2PoGvA4gAAAAAAgdWAcgAABAGH8ZAADIAJKArltQ9csAkoDWCUwAbwVwvf8eBOFgEoCvC2i9fgAAAAAIHQAAIVoYHyGaE86bgElA6wQmgLcCuN5/J4ATAIBDB9YXEAAAQBh/T5oBgAwgCei6BVX/2xOIA+AAEsDWN+B1AAEAAABA6MA6AAEAAML4ywAAQAaQBHTdgqpfBpAEtE5gAngrgOv9dwI4AQA4dGB9AQEAAITxlwEAgAwgCei6BVX/2xOIA+AAEsDWN+B1AHkSjINJALguoPX6AQAAACB0AABY6DA+QjQnxNsn0TgADiABbH0DXgcQAAAAAIQOrAMQAAAgjL8nzQBABpAEdN2Cql8GkAS0TmACeCuA6/13AjgBADh0YH0BAQAAhPGXAQCADCAJ6LoFVf/bE4gD4AASwNY34HUAAQAAAEDowDoAAQAAwvjLAABABpAEdN2Cql8GkAS0TmACeCuA6/33IAgHkwB8XUDr9QMAAABA6AAACNHC+AjRnHDeBEwCWicwAbwVwPX+OwGcAAAcOrC+gAAAAML4e9IMAGQASUDXLaj6355AHAAHkAC2vgGvAwgAAAAAQgfWAQgAABDGXwYAADKAJKDrFlT9MoAkoHUCE8BbAVzvvxPACQDAoQPrCwgAACCMvwwAAGQASUDXLaj6355AHAAHkAC2vgGvA8iTYBxMAsB1Aa3XDwAAAAChAwDAQofxEaI5Id4+icYBcAAJYOsb8DqAAAAAACB0YB2AAAAAYfw9aQYAMoAkoOsWVP0ygCSgdQITwFsBXO+/E8AJAMChA+sLCAAAIIy/DAAAZABJQNctqPrfnkAcAAeQALa+Aa8DCAAAAABCB9YBCAAAEMZfBgAAMoAkoOsWVP0ygCSgdQITwFsBXO+/B0E4mATg6wJarx8AAAAAQgcAQIgWxkeI5oTzJmAS0DqBCeCtAK733wngBADg0IH1BQQAABDG35NmACADSAK6bkHV//YE4gA4gASw9Q14HUAAAAAAEDqwDkAAAIAw/jIAAJABJAFdt6DqlwEkAa0TmADeCuB6/50ATgAADh1YX0AAAABh/GUAACADSAK6bkHV//YE4gA4gASw9Q14HUCeBONgEgCuC2i9fgAAAAAIHQAAFjqMjxDNCfH2STQOgANIAFvfgNcBBAAAAAChA+sABAAACOPvSTMAkAEkAV23oOqXASQBrROYAN4K4Hr/nQBOAAAOHVhfQAAAAGH8ZQAAIANIArpuQdX/9gTiADiABLD1DXgdQAAAAAAQOrAOQAAAgDD+MgAAkAEkAV23oOqXASQBrROYAN4K4Hr/PQjCwSQAXxfQev0AAAAAEDoAAEK0MD5CNCecNwGTgNYJTABvBXC9/04AJwAAhw6sLyAAAIAw/p40AwAZQBLQdQuq/rcnEAfAASSArW/A6wACAAAAgNCBdQACAACE8ZcBAIAMIAnougVVvwwgCWidwATwVgDX++8EcAIAcOjA+gICAAAI4y8DAAAZQBLQdQuq/rcnEAfAASSArW/A6wDyJBgHkwBwXUDr9QMAAABA6AAAsNBhfIRoToi3T6JxABxAAtj6BrwOIAAAAAAIHVgHIAAAQBh/T5oBgAwgCei6BVW/DCAJaJ3ABPBWANf77wRwAgBw6MD6AgIAAAjjLwMAABlAEtB1C6r+tycQB8ABJICtb8DrAAIAAACA0IF1AAIAAITxlwEAgAwgCei6BVW/DCAJaJ3ABPBWANf7/x/aVlkHhH7qqQAAAABJRU5ErkJggg=="/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
|
|
@ -0,0 +1,15 @@
|
|||
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<mask id="mask0_29_3076" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="50" height="50">
|
||||
<rect width="50" height="50" fill="url(#pattern0_29_3076)"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_29_3076)">
|
||||
<rect x="12.4351" y="-14" width="73.2517" height="19" transform="rotate(45 12.4351 -14)" fill="#EC6739"/>
|
||||
<path d="M27.9424 9.41578C28.0273 10.089 28.0612 10.6999 28.0273 11.2543L27.4446 11.2486C27.4955 10.7451 27.4786 10.1285 27.3994 9.40447L27.9424 9.41578ZM26.2341 17.6974C25.9286 17.3919 25.6005 17.0525 25.2498 16.6905C24.8934 16.3228 24.6388 16.0004 24.4748 15.7119C24.322 15.4234 24.2655 15.084 24.2938 14.7049C24.3164 14.5352 24.2881 14.4164 24.2202 14.3486C24.0845 14.2128 23.6036 14.2524 22.7721 14.4617L22.7438 13.879C23.5188 13.7037 24.0731 13.6811 24.4069 13.8112L26.1266 12.0915L25.3177 11.2825L25.691 10.9092L26.8789 12.0971L24.7633 14.2128C24.7746 14.292 24.7746 14.3825 24.7689 14.4787C24.7407 14.7785 24.7633 15.0387 24.8481 15.2706C24.9386 15.5195 25.1479 15.8193 25.4647 16.1588C25.7532 16.4586 26.1153 16.8319 26.5508 17.2675C26.8167 17.5334 27.0939 17.7992 27.3767 18.0708C27.6539 18.3366 27.8746 18.5459 28.0329 18.6817L27.5295 18.9928L26.2341 17.6974ZM28.4911 11.571L29.1587 12.2386L30.0581 11.3391L30.4484 11.7294L29.549 12.6289L30.4428 13.5227L31.3365 12.6289L31.7325 13.0249L30.8387 13.9186L31.5572 14.6371L31.1782 15.0161L30.4597 14.2977L29.334 15.4234L30.2335 16.3228L29.8488 16.7075L28.9494 15.808L27.3258 17.4315L26.9299 17.0356L28.5534 15.4121L27.5465 14.4051C26.7206 14.9369 25.9229 15.1462 25.1593 15.0387L25.2441 14.4674C25.8551 14.5692 26.4943 14.4164 27.1505 14.0092L26.4038 13.2624L26.7884 12.8778L27.6087 13.698C27.8519 13.5113 28.0952 13.302 28.3328 13.0645L28.7796 12.6176L28.1121 11.9501L28.4911 11.571ZM29.17 13.0079L28.8136 13.3643C28.5421 13.6358 28.2649 13.879 27.999 14.0883L28.938 15.0274L30.0638 13.9017L29.17 13.0079ZM34.7193 16.7358L37.429 19.4454L37.0273 19.847L34.3177 17.1374L34.7193 16.7358ZM33.1298 18.0199L36.241 21.1311L35.8394 21.5328L34.923 20.6164L32.4509 23.0884C32.1228 23.4165 31.7721 23.3939 31.4101 23.0318L30.5785 22.2003L30.8953 21.7138C31.1499 22.0023 31.3931 22.2682 31.642 22.5171C31.823 22.6981 31.9927 22.7207 32.1398 22.5736L34.51 20.2034L32.7281 18.4215L33.1298 18.0199ZM34.1367 15.5308L34.3347 16.0682C33.39 16.3794 32.3265 16.4246 31.1442 16.204L31.4327 15.6779C32.4396 15.8476 33.3391 15.7967 34.1367 15.5308ZM33.1128 17.0865L33.3108 17.6239C32.83 17.7766 32.3208 17.8784 31.7891 17.9124L29.0172 20.6842L28.6156 20.2826L30.9745 17.9237C30.5446 17.9011 30.1034 17.8558 29.6451 17.771L29.9336 17.2449C31.1103 17.4485 32.1681 17.3976 33.1128 17.0865ZM40.6873 21.9344L41.1059 22.353L40.0877 23.3712L42.1185 25.4021L39.4598 28.0608L39.0525 27.6535L39.4089 27.2971L37.7854 25.6736L35.8564 27.6026L35.4378 27.184L37.3668 25.255L35.7489 23.6371L35.3925 23.9935L34.9852 23.5862L37.6439 20.9275L39.6691 22.9526L40.6873 21.9344ZM36.1449 23.2411L37.7627 24.859L39.2731 23.3486L37.6553 21.7308L36.1449 23.2411ZM38.1813 25.2776L39.8049 26.9011L41.3152 25.3907L39.6917 23.7672L38.1813 25.2776Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<pattern id="pattern0_29_3076" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_29_3076" transform="scale(0.00390625)"/>
|
||||
</pattern>
|
||||
<image id="image0_29_3076" width="256" height="256" xlink:href="data:image/png;base64,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"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 675 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 288 B |
|
After Width: | Height: | Size: 3.9 KiB |
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
|
||||
/* uni.scss */
|
||||
@import 'uview-plus/theme.scss';
|
||||
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color: #333; // 基本色
|
||||
$uni-text-color-inverse: #fff; // 反色
|
||||
$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable: #c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color: #fff;
|
||||
$uni-bg-color-grey: #f8f8f8;
|
||||
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
|
||||
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color: #c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm: 12px;
|
||||
$uni-font-size-base: 14px;
|
||||
$uni-font-size-lg: 16;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm: 20px;
|
||||
$uni-img-size-base: 26px;
|
||||
$uni-img-size-lg: 40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2c405a; // 文章标题颜色
|
||||
$uni-font-size-title: 20px;
|
||||
$uni-color-subtitle: #555; // 二级标题颜色
|
||||
$uni-font-size-subtitle: 18px;
|
||||
$uni-color-paragraph: #3f536e; // 文章段落颜色
|
||||
$uni-font-size-paragraph: 15px;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
## 0.0.2(2023-09-07)
|
||||
- chore: 更新文档
|
||||
## 0.0.1(2023-09-07)
|
||||
- 初版,可能存在BUG
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// @import '@/uni_modules/lime-ui/style/index.scss';
|
||||
$prefix: l !default;
|
||||
$pre: '--';
|
||||
$backtop: #{$prefix}'-back-top';
|
||||
$prebacktop: #{$pre + $backtop};
|
||||
$font-size-sm: 24rpx !default;
|
||||
$font-size-lg: 40rpx !default;
|
||||
$text-color-2: rgba(0,0,0,0.65) !default;
|
||||
$bg-elevated: #fff !default;
|
||||
$border-color: #d9d9d9 !default;
|
||||
$spacer: 32rpx !default;
|
||||
$spacer-sm: 6rpx !default;
|
||||
$spacer-xl: 96rpx !default;
|
||||
|
||||
$border-radius-circle: 999px !default;
|
||||
$border-radius-sm: 6rpx !default;
|
||||
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
$back-top-font-size: var(--l-back-top-font-size, $font-size-sm);
|
||||
$back-top-icon-size: var(--l-back-top-icon-size, $font-size-lg);
|
||||
$back-top-text-color: var(--l-back-top-text-color, $text-color-2);
|
||||
$back-top-bg-color: var(--l-back-top-bg-color, $bg-elevated);
|
||||
$back-top-border-color: var(--l-back-top-border-color, $border-color);
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
$back-top-font-size: $font-size-sm;
|
||||
$back-top-icon-size: $font-size-lg;
|
||||
$back-top-text-color: $text-color-2;
|
||||
$back-top-bg-color: $bg-elevated;
|
||||
$back-top-border-color: $border-color;
|
||||
/* #endif */
|
||||
.#{$prefix}-back-top {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: transparent;
|
||||
transition: height,opacity .2s ease-in-out;
|
||||
background: $back-top-bg-color;
|
||||
border: 1rpx solid $back-top-border-color;
|
||||
right: $spacer;
|
||||
/* #ifndef APP-NVUE */
|
||||
height: auto;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
&.is-fixed {
|
||||
position: fixed;
|
||||
right: $spacer;
|
||||
bottom:$spacer-xl;
|
||||
}
|
||||
&.is-hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
&.is-circle {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
border-radius: $border-radius-circle;
|
||||
}
|
||||
&.is-square {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
padding: $spacer-sm;
|
||||
border-radius: $border-radius-sm;
|
||||
}
|
||||
&__text {
|
||||
font-size: $back-top-font-size;
|
||||
color: $back-top-text-color;
|
||||
line-height: 24rpx;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: $back-top-icon-size;
|
||||
}
|
||||
&__anchor {
|
||||
position: absolute;
|
||||
padding: 1rpx;
|
||||
bottom: -100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
<template>
|
||||
<view class="l-back-top__wrap">
|
||||
<view ref="l-back-top__anchor" class="l-back-top__anchor" v-if="props.offset" :style="{bottom: (props.offset||0)*-1 + 'px'}"></view>
|
||||
<view class="l-back-top l-class" :class="classes" :style="[styles, lStyle]" :aria-role="ariaRole || 'button'" @click="toTop">
|
||||
<view class="l-back-top__icon l-class-icon" aria-hidden v-if="props.icon || $slots.icon">
|
||||
<!-- <block v-if="!$slots.icon">🡡</block> -->
|
||||
<l-icon :name="props.icon"></l-icon>
|
||||
<slot name="icon"></slot>
|
||||
</view>
|
||||
<text v-if="props.text" :class="`${name}__text`" class="l-class-text">{{text}}</text>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { ref, computed, getCurrentInstance, onMounted, onUnmounted, defineComponent } from '@/uni_modules/lime-shared/vue'
|
||||
import BackTopProps from './props'
|
||||
import { addUnit } from '@/uni_modules/lime-shared/addUnit';
|
||||
import { useIntersectionObserver } from '@/uni_modules/lime-shared/useIntersectionObserver'
|
||||
// #ifdef APP-NVUE
|
||||
const dom = uni.requireNativePlugin('dom')
|
||||
// #endif
|
||||
const name = 'l-back-top'
|
||||
/**
|
||||
* LimeBackTop 返回顶部
|
||||
* @description 用于当页面过长往下滑动时,帮助用户快速回到页面顶部集
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=14509
|
||||
* @@property {String|Boolean} icon 图标名称
|
||||
* @property {String} text 文案
|
||||
* @property {String} topAnchor nvue需指定要滚到ref节点
|
||||
* @property {Number} offset 滚动高度达到此参数值才出现, nvue无效, 默认 200
|
||||
* @property {Number} duration 回到顶部过渡时间ms, nvue无效 100
|
||||
* @property {Boolean} fixed 是否绝对定位固定到屏幕右下方,默认为true
|
||||
* @property {string} shape 形状,circle, square, 默认circle
|
||||
* @value circle 圆
|
||||
* @value square 方
|
||||
* @event {Function} to-top 点击
|
||||
*/
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: BackTopProps,
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
},
|
||||
emits: ['click'],
|
||||
externalClasses: ['l-class', 'l-class-icon', 'l-class-text'],
|
||||
setup(props, { emit }) {
|
||||
const { fixed, bottom, right } = props;
|
||||
const context = getCurrentInstance()
|
||||
const show = ref(false)
|
||||
const classes = computed(() => ({
|
||||
[`is-${props.shape}`]: props.shape,
|
||||
[`is-fixed`]: fixed,
|
||||
[`is-hidden`]: !show.value,
|
||||
}))
|
||||
|
||||
const styles = computed(() => {
|
||||
const style: any = {}
|
||||
if(bottom) style.bottom = addUnit(bottom)
|
||||
if(right) style.right = addUnit(right)
|
||||
return style
|
||||
})
|
||||
const target = ref(null)
|
||||
const wrapCallback = (res: UniApp.ObserveResult) => {
|
||||
if (props.offset) {
|
||||
show.value = res.boundingClientRect.top - res.relativeRect.top < 0 || res.intersectionRatio > 0;
|
||||
}
|
||||
};
|
||||
const toTop = () => {
|
||||
emit('click')
|
||||
// #ifdef APP-NVUE
|
||||
if(props.target) {
|
||||
dom.scrollToElement(context.parent.refs[props.target], {
|
||||
offset: 0
|
||||
})
|
||||
} else {
|
||||
console.error(`nvue页面需要指定滚动元素的ref`)
|
||||
}
|
||||
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
uni.pageScrollTo({
|
||||
scrollTop: 0,
|
||||
duration: props.duration,
|
||||
})
|
||||
// #endif
|
||||
if(props.offset) {show.value = false}
|
||||
}
|
||||
|
||||
const { stop } = useIntersectionObserver(target, wrapCallback, { context })
|
||||
onMounted(() => {
|
||||
if (props.offset) {
|
||||
// #ifdef APP-NVUE
|
||||
target.value = context.refs[`${name}__anchor`]
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
target.value = `.${name}__anchor`
|
||||
// #endif
|
||||
} else {
|
||||
show.value = true
|
||||
stop()
|
||||
}
|
||||
})
|
||||
onUnmounted(stop)
|
||||
return {
|
||||
classes,
|
||||
styles,
|
||||
toTop,
|
||||
props,
|
||||
name
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './index';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// @ts-nocheck
|
||||
// import {BackTopProps} from './type'
|
||||
export const ariaProps = {
|
||||
ariaHidden: Boolean,
|
||||
ariaRole: String,
|
||||
ariaLabel: String,
|
||||
ariaLabelledby: String,
|
||||
ariaDescribedby: String,
|
||||
ariaBusy: Boolean,
|
||||
lStyle: String
|
||||
}
|
||||
export default {
|
||||
// value: {
|
||||
// type: Number,
|
||||
// default: 0
|
||||
// },
|
||||
fixed: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
icon: {
|
||||
type: [String, Boolean],
|
||||
default: 'bx:arrow-to-top'
|
||||
},
|
||||
text: String,
|
||||
bottom: {
|
||||
type: [Number, String],
|
||||
// default: 66,
|
||||
},
|
||||
right: {
|
||||
type: [Number, String],
|
||||
// default: 16,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
offset: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
target: String,
|
||||
shape: {
|
||||
type: String,
|
||||
default: 'circle' // square
|
||||
},
|
||||
// scrollView: Boolean,
|
||||
...ariaProps
|
||||
// square: Boolean,
|
||||
// plain: Boolean as propType<BackTopProps['plain']>,
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// @ts-nocheck
|
||||
export interface BackTopProps {
|
||||
/**
|
||||
* 滚动到指定对象
|
||||
*/
|
||||
target?: string;
|
||||
/**
|
||||
* 是否绝对定位固定到屏幕右下方
|
||||
* @default true
|
||||
*/
|
||||
fixed?: boolean;
|
||||
/**
|
||||
* 图标
|
||||
* @default 'bx:arrow-to-top'
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 文案
|
||||
* @default ''
|
||||
*/
|
||||
text?: string;
|
||||
/**
|
||||
* 预设的样式类型
|
||||
* @default ''
|
||||
*/
|
||||
type?: 'primary' | 'success' | 'warning' | 'danger' | 'default';
|
||||
/**
|
||||
* 页面垂直滚动多高后出现
|
||||
* @default 0
|
||||
*/
|
||||
offset?: number
|
||||
/**
|
||||
* 距离页面右侧距离
|
||||
* @default 16
|
||||
*/
|
||||
right?: number|string
|
||||
/**
|
||||
* 距离页面底部距离
|
||||
* @default 66
|
||||
*/
|
||||
bottom?: number|string
|
||||
/**
|
||||
* 圆形
|
||||
*/
|
||||
round?: boolean
|
||||
/**
|
||||
* 方形
|
||||
*/
|
||||
square?: boolean
|
||||
/**
|
||||
* 朴素
|
||||
*/
|
||||
plain?: boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<scroller ref="scroller" @scroll="scroll">
|
||||
<view ref="topAnchor"><text></text></view>
|
||||
<!-- #endif -->
|
||||
<demo-block title="组件类型">
|
||||
<demo-cell title="圆形" @click="onClick('circle')"></demo-cell>
|
||||
<demo-cell title="方形" @click="onClick('square')"></demo-cell>
|
||||
</demo-block>
|
||||
|
||||
<!-- nvue 需要设置topAnchor -->
|
||||
<l-back-top bottom="90" target="topAnchor" :shape="shape" text="顶部" :offset="300"></l-back-top>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
</scroller>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
shape: 'circle'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick(type) {
|
||||
this.shape = type
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"id": "lime-back-top",
|
||||
"displayName": "back-top 返回顶部 lime-back-top",
|
||||
"version": "0.0.2",
|
||||
"description": "uniapp vue3 实现的返回顶部按钮,页面过长往下滑动会出现返回顶部的便捷操作,帮助用户快速回到页面顶部。目前仅在H5和微信小程序上测试,vue2需要配置@vue/composition-api",
|
||||
"keywords": [
|
||||
"back-top",
|
||||
"返回顶部"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"lime-shared",
|
||||
"lime-icon",
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
# lime-back-top
|
||||
- 用于当页面过长往下滑动时,帮助用户快速回到页面顶部。
|
||||
- 基于uniapp vue3
|
||||
- Q群719441207
|
||||
|
||||
### 安装
|
||||
- 在市场导入插件即可在任意页面使用,无须再`import`
|
||||
|
||||
|
||||
### 使用
|
||||
- 提供简单的使用示例,更多请查看下方的demo
|
||||
|
||||
```html
|
||||
<l-back-top text="顶部"/>
|
||||
```
|
||||
|
||||
|
||||
#### 形状
|
||||
- shape: 有circle,square
|
||||
|
||||
```html
|
||||
<l-back-top shape="circle"></l-back-top>
|
||||
```
|
||||
|
||||
### 查看示例
|
||||
- 导入后直接使用这个标签查看演示效果
|
||||
|
||||
```html
|
||||
// 代码位于 uni_modules/lime-back-top/compoents/lime-back-top
|
||||
<lime-back-top />
|
||||
```
|
||||
|
||||
### 插件标签
|
||||
- 默认 l-back-top 为 component
|
||||
- 默认 lime-back-top 为 demo
|
||||
|
||||
### 关于vue2的使用方式
|
||||
- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
|
||||
- 关键代码是: 在main.js中 在vue2部分加上这一段即可.
|
||||
|
||||
```js
|
||||
// vue2
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
```
|
||||
|
||||
|
||||
另外插件也用到了TS,vue2可能会遇过官方的TS版本过低的问题,找到HX目录下的`compile-typescript`目录
|
||||
```cmd
|
||||
// \HBuilderX\plugins\compile-typescript
|
||||
yarn add typescript -D
|
||||
- or -
|
||||
npm install typescript -D
|
||||
```
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
|
||||
| icon | [图标](https://ext.dcloud.net.cn/plugin?id=14057)。值为 false 表示不显示图标。不传表示使用默认图标 'bx:arrow-to-top' | <em>string</em> | `` |
|
||||
| text | 方案 | <em>string</em> | `` |
|
||||
| fixed | 是否绝对定位固定到屏幕右下方 | <em>boolean </em> | `true` |
|
||||
| duration | 回到顶部所需时间(ms), nvue无效 | <em>number</em> | `100` |
|
||||
| offset | 页面垂直滚动多高后出现, nvue无效 | <em>number</em> | `200` |
|
||||
| target | nvue需要定位滚动到指定对象 | <em>string</em> | `` |
|
||||
| shape | 形状: `circle`、`square` | <em>string</em> | `circle` |
|
||||
|
||||
### Events
|
||||
| 参数 | 说明 | 参数 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- |
|
||||
| click | 点击触发 | `-` |
|
||||
|
||||
|
||||
### CSS 变量
|
||||
组件提供了下列 CSS 变量,可用于自定义样式。
|
||||
名称 | 默认值 | 描述
|
||||
-- | -- | --
|
||||
--l-back-top-font-size | 24rpx | -
|
||||
--l-back-top-icon-size | 40rpx | -
|
||||
--l-back-top-text-color | rgba(0,0,0,0.65) | -
|
||||
--l-back-top-bg-color | #fff | -
|
||||
--l-back-top-border-color | #d9d9d9 | -
|
||||
|
||||
## 打赏
|
||||
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
||||
|
|
@ -0,0 +1,7 @@
|
|||
## 0.0.3(2023-09-05)
|
||||
- chore: 更新文档
|
||||
- feat: 默认使用官方API
|
||||
## 0.0.2(2023-08-13)
|
||||
- chore: 更新文档
|
||||
## 0.0.1(2023-08-13)
|
||||
- 初次上传 可能存在BUG
|
||||
|
|
@ -0,0 +1,961 @@
|
|||
/* #ifndef APP-NVUE */
|
||||
$prefix: l !default;
|
||||
@font-face {
|
||||
font-family: $prefix;
|
||||
src: url('https://tdesign.gtimg.com/icon/0.1.2/fonts/t.ttf') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.#{$prefix}-icon {
|
||||
font-family: $prefix !important;
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-add-circle:before {
|
||||
content: '\E001';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-add-rectangle:before {
|
||||
content: '\E002';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-add:before {
|
||||
content: '\E003';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-app:before {
|
||||
content: '\E004';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-arrow-down-rectangle:before {
|
||||
content: '\E005';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-arrow-down:before {
|
||||
content: '\E006';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-arrow-left:before {
|
||||
content: '\E007';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-arrow-right:before {
|
||||
content: '\E008';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-arrow-up:before {
|
||||
content: '\E009';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-attach:before {
|
||||
content: '\E00A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-backtop-rectangle:before {
|
||||
content: '\E00B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-backtop:before {
|
||||
content: '\E00C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-backward:before {
|
||||
content: '\E00D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-barcode:before {
|
||||
content: '\E00E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-books:before {
|
||||
content: '\E00F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-browse-off:before {
|
||||
content: '\E010';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-browse:before {
|
||||
content: '\E011';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-bulletpoint:before {
|
||||
content: '\E012';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-calendar:before {
|
||||
content: '\E013';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-call:before {
|
||||
content: '\E014';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-down-small:before {
|
||||
content: '\E015';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-down:before {
|
||||
content: '\E016';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-left-small:before {
|
||||
content: '\E017';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-left:before {
|
||||
content: '\E018';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-right-small:before {
|
||||
content: '\E019';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-right:before {
|
||||
content: '\E01A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-up-small:before {
|
||||
content: '\E01B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-caret-up:before {
|
||||
content: '\E01C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-cart:before {
|
||||
content: '\E01D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chart-bar:before {
|
||||
content: '\E01E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chart-bubble:before {
|
||||
content: '\E01F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chart-pie:before {
|
||||
content: '\E020';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chart:before {
|
||||
content: '\E021';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chat:before {
|
||||
content: '\E022';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-check-circle-filled:before {
|
||||
content: '\E023';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-check-circle:before {
|
||||
content: '\E024';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-check-rectangle-filled:before {
|
||||
content: '\E025';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-check-rectangle:before {
|
||||
content: '\E026';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-check:before {
|
||||
content: '\E027';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-down-circle:before {
|
||||
content: '\E028';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-down-rectangle:before {
|
||||
content: '\E029';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-down:before {
|
||||
content: '\E02A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-left-circle:before {
|
||||
content: '\E02B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-left-double:before {
|
||||
content: '\E02C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-left-rectangle:before {
|
||||
content: '\E02D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-left:before {
|
||||
content: '\E02E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-right-circle:before {
|
||||
content: '\E02F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-right-double:before {
|
||||
content: '\E030';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-right-rectangle:before {
|
||||
content: '\E031';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-right:before {
|
||||
content: '\E032';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-up-circle:before {
|
||||
content: '\E033';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-up-rectangle:before {
|
||||
content: '\E034';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-chevron-up:before {
|
||||
content: '\E035';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-circle:before {
|
||||
content: '\E036';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-clear:before {
|
||||
content: '\E037';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-close-circle-filled:before {
|
||||
content: '\E038';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-close-circle:before {
|
||||
content: '\E039';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-close-rectangle:before {
|
||||
content: '\E03A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-close:before {
|
||||
content: '\E03B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-cloud-download:before {
|
||||
content: '\E03C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-cloud-upload:before {
|
||||
content: '\E03D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-cloud:before {
|
||||
content: '\E03E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-code:before {
|
||||
content: '\E03F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-control-platform:before {
|
||||
content: '\E040';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-creditcard:before {
|
||||
content: '\E041';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-dashboard:before {
|
||||
content: '\E042';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-delete:before {
|
||||
content: '\E043';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-desktop:before {
|
||||
content: '\E044';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-discount-filled:before {
|
||||
content: '\E045';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-discount:before {
|
||||
content: '\E046';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-download:before {
|
||||
content: '\E047';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-edit-1:before {
|
||||
content: '\E048';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-edit:before {
|
||||
content: '\E049';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-ellipsis:before {
|
||||
content: '\E04A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-enter:before {
|
||||
content: '\E04B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-error-circle-filled:before {
|
||||
content: '\E04C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-error-circle:before {
|
||||
content: '\E04D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-error:before {
|
||||
content: '\E04E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-add:before {
|
||||
content: '\E04F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-copy:before {
|
||||
content: '\E050';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-excel:before {
|
||||
content: '\E051';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-icon:before {
|
||||
content: '\E052';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-image:before {
|
||||
content: '\E053';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-paste:before {
|
||||
content: '\E054';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-pdf:before {
|
||||
content: '\E055';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-powerpoint:before {
|
||||
content: '\E056';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-unknown:before {
|
||||
content: '\E057';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file-word:before {
|
||||
content: '\E058';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-file:before {
|
||||
content: '\E059';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-filter-clear:before {
|
||||
content: '\E05A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-filter:before {
|
||||
content: '\E05B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-flag:before {
|
||||
content: '\E05C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-folder-add:before {
|
||||
content: '\E05D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-folder-open:before {
|
||||
content: '\E05E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-folder:before {
|
||||
content: '\E05F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-fork:before {
|
||||
content: '\E060';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-format-horizontal-align-bottom:before {
|
||||
content: '\E061';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-format-horizontal-align-center:before {
|
||||
content: '\E062';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-format-horizontal-align-top:before {
|
||||
content: '\E063';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-format-vertical-align-center:before {
|
||||
content: '\E064';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-format-vertical-align-left:before {
|
||||
content: '\E065';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-format-vertical-align-right:before {
|
||||
content: '\E066';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-forward:before {
|
||||
content: '\E067';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-fullscreen-exit:before {
|
||||
content: '\E068';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-fullscreen:before {
|
||||
content: '\E069';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-gender-female:before {
|
||||
content: '\E06A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-gender-male:before {
|
||||
content: '\E06B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-gift:before {
|
||||
content: '\E06C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-heart-filled:before {
|
||||
content: '\E06D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-heart:before {
|
||||
content: '\E06E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-help-circle-filled:before {
|
||||
content: '\E06F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-help-circle:before {
|
||||
content: '\E070';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-help:before {
|
||||
content: '\E071';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-history:before {
|
||||
content: '\E072';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-home:before {
|
||||
content: '\E073';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-hourglass:before {
|
||||
content: '\E074';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-image-error:before {
|
||||
content: '\E075';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-image:before {
|
||||
content: '\E076';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-info-circle-filled:before {
|
||||
content: '\E077';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-info-circle:before {
|
||||
content: '\E078';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-internet:before {
|
||||
content: '\E079';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-jump:before {
|
||||
content: '\E07A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-laptop:before {
|
||||
content: '\E07B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-layers:before {
|
||||
content: '\E07C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-link-unlink:before {
|
||||
content: '\E07D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-link:before {
|
||||
content: '\E07E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-loading:before {
|
||||
content: '\E07F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-location:before {
|
||||
content: '\E080';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-lock-off:before {
|
||||
content: '\E081';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-lock-on:before {
|
||||
content: '\E082';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-login:before {
|
||||
content: '\E083';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-android:before {
|
||||
content: '\E084';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-apple-filled:before {
|
||||
content: '\E085';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-apple:before {
|
||||
content: '\E086';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-chrome-filled:before {
|
||||
content: '\E087';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-chrome:before {
|
||||
content: '\E088';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-codepen:before {
|
||||
content: '\E089';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-github-filled:before {
|
||||
content: '\E08A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-github:before {
|
||||
content: '\E08B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-ie-filled:before {
|
||||
content: '\E08C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-ie:before {
|
||||
content: '\E08D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-qq:before {
|
||||
content: '\E08E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-wechat:before {
|
||||
content: '\E08F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-wecom:before {
|
||||
content: '\E090';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-windows-filled:before {
|
||||
content: '\E091';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logo-windows:before {
|
||||
content: '\E092';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-logout:before {
|
||||
content: '\E093';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-mail:before {
|
||||
content: '\E094';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-menu-fold:before {
|
||||
content: '\E095';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-menu-unfold:before {
|
||||
content: '\E096';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-minus-circle-filled:before {
|
||||
content: '\E097';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-minus-circle:before {
|
||||
content: '\E098';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-minus-rectangle:before {
|
||||
content: '\E099';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-mirror:before {
|
||||
content: '\E09A';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-mobile-vibrate:before {
|
||||
content: '\E09B';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-mobile:before {
|
||||
content: '\E09C';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-money-circle:before {
|
||||
content: '\E09D';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-more:before {
|
||||
content: '\E09E';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-move:before {
|
||||
content: '\E09F';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-next:before {
|
||||
content: '\E0A0';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-notification-filled:before {
|
||||
content: '\E0A1';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-notification:before {
|
||||
content: '\E0A2';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-order-adjustment-column:before {
|
||||
content: '\E0A3';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-order-ascending:before {
|
||||
content: '\E0A4';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-order-descending:before {
|
||||
content: '\E0A5';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-page-first:before {
|
||||
content: '\E0A6';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-page-last:before {
|
||||
content: '\E0A7';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-pause-circle-filled:before {
|
||||
content: '\E0A8';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-photo:before {
|
||||
content: '\E0A9';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-pin-filled:before {
|
||||
content: '\E0AA';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-pin:before {
|
||||
content: '\E0AB';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-play-circle-filled:before {
|
||||
content: '\E0AC';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-play-circle-stroke:before {
|
||||
content: '\E0AD';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-play-circle:before {
|
||||
content: '\E0AE';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-play:before {
|
||||
content: '\E0AF';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-poweroff:before {
|
||||
content: '\E0B0';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-precise-monitor:before {
|
||||
content: '\E0B1';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-previous:before {
|
||||
content: '\E0B2';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-print:before {
|
||||
content: '\E0B3';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-qrcode:before {
|
||||
content: '\E0B4';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-queue:before {
|
||||
content: '\E0B5';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-rectangle:before {
|
||||
content: '\E0B6';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-refresh:before {
|
||||
content: '\E0B7';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-relativity:before {
|
||||
content: '\E0B8';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-remove:before {
|
||||
content: '\E0B9';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-rollback:before {
|
||||
content: '\E0BA';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-rollfront:before {
|
||||
content: '\E0BB';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-root-list:before {
|
||||
content: '\E0BC';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-rotation:before {
|
||||
content: '\E0BD';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-round:before {
|
||||
content: '\E0BE';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-save:before {
|
||||
content: '\E0BF';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-scan:before {
|
||||
content: '\E0C0';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-search:before {
|
||||
content: '\E0C1';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-secured:before {
|
||||
content: '\E0C2';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-server:before {
|
||||
content: '\E0C3';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-service:before {
|
||||
content: '\E0C4';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-setting:before {
|
||||
content: '\E0C5';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-share:before {
|
||||
content: '\E0C6';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-shop:before {
|
||||
content: '\E0C7';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-slash:before {
|
||||
content: '\E0C8';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-sound:before {
|
||||
content: '\E0C9';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-star-filled:before {
|
||||
content: '\E0CA';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-star:before {
|
||||
content: '\E0CB';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-stop-circle-1:before {
|
||||
content: '\E0CC';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-stop-circle-filled:before {
|
||||
content: '\E0CD';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-stop-circle:before {
|
||||
content: '\E0CE';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-stop:before {
|
||||
content: '\E0CF';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-swap-left:before {
|
||||
content: '\E0D0';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-swap-right:before {
|
||||
content: '\E0D1';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-swap:before {
|
||||
content: '\E0D2';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-thumb-down:before {
|
||||
content: '\E0D3';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-thumb-up:before {
|
||||
content: '\E0D4';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-time-filled:before {
|
||||
content: '\E0D5';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-time:before {
|
||||
content: '\E0D6';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-tips:before {
|
||||
content: '\E0D7';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-tools:before {
|
||||
content: '\E0D8';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-unfold-less:before {
|
||||
content: '\E0D9';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-unfold-more:before {
|
||||
content: '\E0DA';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-upload:before {
|
||||
content: '\E0DB';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-usb:before {
|
||||
content: '\E0DC';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-user-add:before {
|
||||
content: '\E0DD';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-user-avatar:before {
|
||||
content: '\E0DE';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-user-circle:before {
|
||||
content: '\E0DF';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-user-clear:before {
|
||||
content: '\E0E0';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-user-talk:before {
|
||||
content: '\E0E1';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-user:before {
|
||||
content: '\E0E2';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-usergroup-add:before {
|
||||
content: '\E0E3';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-usergroup-clear:before {
|
||||
content: '\E0E4';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-usergroup:before {
|
||||
content: '\E0E5';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-video:before {
|
||||
content: '\E0E6';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-view-column:before {
|
||||
content: '\E0E7';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-view-list:before {
|
||||
content: '\E0E8';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-view-module:before {
|
||||
content: '\E0E9';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-wallet:before {
|
||||
content: '\E0EA';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-wifi:before {
|
||||
content: '\E0EB';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-zoom-in:before {
|
||||
content: '\E0EC';
|
||||
}
|
||||
|
||||
.#{$prefix}-icon-zoom-out:before {
|
||||
content: '\E0ED';
|
||||
}
|
||||
/* #endif */
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
const list = [
|
||||
'add-circle',
|
||||
'add-rectangle',
|
||||
'add',
|
||||
'app',
|
||||
'arrow-down-rectangle',
|
||||
'arrow-down',
|
||||
'arrow-left',
|
||||
'arrow-right',
|
||||
'arrow-up',
|
||||
'attach',
|
||||
'backtop-rectangle',
|
||||
'backtop',
|
||||
'backward',
|
||||
'barcode',
|
||||
'books',
|
||||
'browse-off',
|
||||
'browse',
|
||||
'bulletpoint',
|
||||
'calendar',
|
||||
'call',
|
||||
'caret-down-small',
|
||||
'caret-down',
|
||||
'caret-left-small',
|
||||
'caret-left',
|
||||
'caret-right-small',
|
||||
'caret-right',
|
||||
'caret-up-small',
|
||||
'caret-up',
|
||||
'cart',
|
||||
'chart-bar',
|
||||
'chart-bubble',
|
||||
'chart-pie',
|
||||
'chart',
|
||||
'chat',
|
||||
'check-circle-filled',
|
||||
'check-circle',
|
||||
'check-rectangle-filled',
|
||||
'check-rectangle',
|
||||
'check',
|
||||
'chevron-down-circle',
|
||||
'chevron-down-rectangle',
|
||||
'chevron-down',
|
||||
'chevron-left-circle',
|
||||
'chevron-left-double',
|
||||
'chevron-left-rectangle',
|
||||
'chevron-left',
|
||||
'chevron-right-circle',
|
||||
'chevron-right-double',
|
||||
'chevron-right-rectangle',
|
||||
'chevron-right',
|
||||
'chevron-up-circle',
|
||||
'chevron-up-rectangle',
|
||||
'chevron-up',
|
||||
'circle',
|
||||
'clear',
|
||||
'close-circle-filled',
|
||||
'close-circle',
|
||||
'close-rectangle',
|
||||
'close',
|
||||
'cloud-download',
|
||||
'cloud-upload',
|
||||
'cloud',
|
||||
'code',
|
||||
'control-platform',
|
||||
'creditcard',
|
||||
'dashboard',
|
||||
'delete',
|
||||
'desktop',
|
||||
'discount-filled',
|
||||
'discount',
|
||||
'download',
|
||||
'edit-1',
|
||||
'edit',
|
||||
'ellipsis',
|
||||
'enter',
|
||||
'error-circle-filled',
|
||||
'error-circle',
|
||||
'error',
|
||||
'file-add',
|
||||
'file-copy',
|
||||
'file-excel',
|
||||
'file-icon',
|
||||
'file-image',
|
||||
'file-paste',
|
||||
'file-pdf',
|
||||
'file-powerpoint',
|
||||
'file-unknown',
|
||||
'file-word',
|
||||
'file',
|
||||
'filter-clear',
|
||||
'filter',
|
||||
'flag',
|
||||
'folder-add',
|
||||
'folder-open',
|
||||
'folder',
|
||||
'fork',
|
||||
'format-horizontal-align-bottom',
|
||||
'format-horizontal-align-center',
|
||||
'format-horizontal-align-top',
|
||||
'format-vertical-align-center',
|
||||
'format-vertical-align-left',
|
||||
'format-vertical-align-right',
|
||||
'forward',
|
||||
'fullscreen-exit',
|
||||
'fullscreen',
|
||||
'gender-female',
|
||||
'gender-male',
|
||||
'gift',
|
||||
'heart-filled',
|
||||
'heart',
|
||||
'help-circle-filled',
|
||||
'help-circle',
|
||||
'help',
|
||||
'history',
|
||||
'home',
|
||||
'hourglass',
|
||||
'image-error',
|
||||
'image',
|
||||
'info-circle-filled',
|
||||
'info-circle',
|
||||
'internet',
|
||||
'jump',
|
||||
'laptop',
|
||||
'layers',
|
||||
'link-unlink',
|
||||
'link',
|
||||
'loading',
|
||||
'location',
|
||||
'lock-off',
|
||||
'lock-on',
|
||||
'login',
|
||||
'logo-android',
|
||||
'logo-apple-filled',
|
||||
'logo-apple',
|
||||
'logo-chrome-filled',
|
||||
'logo-chrome',
|
||||
'logo-codepen',
|
||||
'logo-github-filled',
|
||||
'logo-github',
|
||||
'logo-ie-filled',
|
||||
'logo-ie',
|
||||
'logo-qq',
|
||||
'logo-wechat',
|
||||
'logo-wecom',
|
||||
'logo-windows-filled',
|
||||
'logo-windows',
|
||||
'logout',
|
||||
'mail',
|
||||
'menu-fold',
|
||||
'menu-unfold',
|
||||
'minus-circle-filled',
|
||||
'minus-circle',
|
||||
'minus-rectangle',
|
||||
'mirror',
|
||||
'mobile-vibrate',
|
||||
'mobile',
|
||||
'money-circle',
|
||||
'more',
|
||||
'move',
|
||||
'next',
|
||||
'notification-filled',
|
||||
'notification',
|
||||
'order-adjustment-column',
|
||||
'order-ascending',
|
||||
'order-descending',
|
||||
'page-first',
|
||||
'page-last',
|
||||
'pause-circle-filled',
|
||||
'photo',
|
||||
'pin-filled',
|
||||
'pin',
|
||||
'play-circle-filled',
|
||||
'play-circle-stroke',
|
||||
'play-circle',
|
||||
'play',
|
||||
'poweroff',
|
||||
'precise-monitor',
|
||||
'previous',
|
||||
'print',
|
||||
'qrcode',
|
||||
'queue',
|
||||
'rectangle',
|
||||
'refresh',
|
||||
'relativity',
|
||||
'remove',
|
||||
'rollback',
|
||||
'rollfront',
|
||||
'root-list',
|
||||
'rotation',
|
||||
'round',
|
||||
'save',
|
||||
'scan',
|
||||
'search',
|
||||
'secured',
|
||||
'server',
|
||||
'service',
|
||||
'setting',
|
||||
'share',
|
||||
'shop',
|
||||
'slash',
|
||||
'sound',
|
||||
'star-filled',
|
||||
'star',
|
||||
'stop-circle-1',
|
||||
'stop-circle-filled',
|
||||
'stop-circle',
|
||||
'stop',
|
||||
'swap-left',
|
||||
'swap-right',
|
||||
'swap',
|
||||
'thumb-down',
|
||||
'thumb-up',
|
||||
'time-filled',
|
||||
'time',
|
||||
'tips',
|
||||
'tools',
|
||||
'unfold-less',
|
||||
'unfold-more',
|
||||
'upload',
|
||||
'usb',
|
||||
'user-add',
|
||||
'user-avatar',
|
||||
'user-circle',
|
||||
'user-clear',
|
||||
'user-talk',
|
||||
'user',
|
||||
'usergroup-add',
|
||||
'usergroup-clear',
|
||||
'usergroup',
|
||||
'video',
|
||||
'view-column',
|
||||
'view-list',
|
||||
'view-module',
|
||||
'wallet',
|
||||
'wifi',
|
||||
'zoom-in',
|
||||
'zoom-out',
|
||||
]
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 公共前缀
|
||||
// @import '@/uni_modules/lime-ui/style/index.scss';
|
||||
/* #ifndef APP-NVUE */
|
||||
// @import './icon';
|
||||
/* #endif */
|
||||
|
||||
$prefix: l !default;
|
||||
$icon: #{$prefix}-icon;
|
||||
|
||||
/* #ifndef APP-NVUE || UNI-APP-X */
|
||||
:host {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
.#{$icon} {
|
||||
/* #ifndef APP-NVUE || UNI-APP-X */
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE || UNI-APP-X */
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
/* #endif */
|
||||
|
||||
&--font {
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
font-size: inherit;
|
||||
|
||||
/* #ifndef APP-NVUE || UNI-APP-X */
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
// -webkit-font-smoothing: antialiased;
|
||||
// -moz-osx-font-smoothing: grayscale;
|
||||
// -webkit-background-clip: text;
|
||||
// background-clip: text;
|
||||
/* #endif */
|
||||
}
|
||||
/* #ifndef APP-NVUE || UNI-APP-X */
|
||||
&--image {
|
||||
&.is-inherit {
|
||||
background-color: currentColor;
|
||||
mask: var(--l-icon) no-repeat;
|
||||
mask-size: 100% 100%;
|
||||
// -webkit-mask: var(--l-icon) no-repeat;
|
||||
// -webkit-mask-size: 100% 100%;
|
||||
}
|
||||
&:not(.is-inherit) {
|
||||
background: var(--l-icon) no-repeat;
|
||||
background-size: 100% 100%;
|
||||
background-color: transparent;
|
||||
// -webkit-background: var(--l-icon) no-repeat;
|
||||
// -webkit-background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
&__image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
<template>
|
||||
<!-- #ifdef UNI-APP-X -->
|
||||
<view class="l-icon" @click="onClick">
|
||||
<text>未完成</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script lang="uts">
|
||||
// #ifdef UNI-APP-X
|
||||
const name : string = 'l-icon';
|
||||
export default {
|
||||
name,
|
||||
props: {
|
||||
ariaHidden: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
ariaRole: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ariaLabel: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ariaLabelledby: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ariaDescribedby: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ariaBusy: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
lStyle: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// type: String,
|
||||
inherit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
iconUrl: '',
|
||||
hasImage: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasHost() : boolean {
|
||||
return this.name.indexOf('/') !== -1
|
||||
},
|
||||
styles() : any {
|
||||
return {
|
||||
width: this.size,
|
||||
height: this.size,
|
||||
}
|
||||
},
|
||||
isImage() : boolean {
|
||||
return this.hasHost || /\.(.+)$/i.test(this.name) || this.hasImage
|
||||
},
|
||||
classes() : any {
|
||||
// const { prefix } = this
|
||||
// const name = 'l-icon'
|
||||
const iconPrefix : string = this.prefix.length > 0 ? this.prefix : name
|
||||
const iconName : string = `${iconPrefix}-${this.name}`
|
||||
const cls : string[] = []
|
||||
if (!this.isImage && this.prefix.length > 0) {
|
||||
cls.push(iconPrefix)
|
||||
}
|
||||
if (!this.isImage) {
|
||||
cls.push(iconName)
|
||||
cls.push(`${name}--font`)
|
||||
}
|
||||
if (this.isImage) {
|
||||
cls.push(`${name}--image`)
|
||||
}
|
||||
if (this.isImage && (this.color.length > 0 || this.inherit)) {
|
||||
cls.push(`is-inherit`)
|
||||
}
|
||||
return cls.join(' ')
|
||||
// return {
|
||||
// [iconPrefix]: !this.isImage && prefix,
|
||||
// [iconName]: !this.isImage,
|
||||
// [`${name}--image`]: this.isImage,
|
||||
// [`${name}--font`]: !this.isImage,
|
||||
// [`is-inherit`]: this.isImage && (this.color || this.inherit)
|
||||
// }
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClick() { },
|
||||
imageLoad() { },
|
||||
imageError() { },
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './index.scss';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<!-- #ifndef UNI-APP-X -->
|
||||
<view
|
||||
class="l-icon l-class"
|
||||
:class="classes"
|
||||
:style="[styles, lStyle]"
|
||||
:aria-hidden="ariaHidden"
|
||||
:aria-label="ariaLabel"
|
||||
:aria-role="ariaRole"
|
||||
@click="onClick">
|
||||
<image v-if="iconUrl" hidden class="l-icon__image" :src="iconUrl" @load="imageLoad" @error="imageError"></image>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
/**
|
||||
* LimeIcon 图标
|
||||
* @description ICON集
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=14057
|
||||
* @property {String} name 图标名称
|
||||
* @property {String} color 颜色
|
||||
* @property {String} size 尺寸
|
||||
* @property {String} prefix 字体图标前缀
|
||||
* @property {Boolean} inherit 是否继承颜色
|
||||
* @event {Function} click 加载完成触发
|
||||
*/
|
||||
// #ifndef UNI-APP-X
|
||||
export {default} from './lIcon'
|
||||
// #endif
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './index.scss';
|
||||
</style>
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
// @ts-nocheck
|
||||
import { computed, defineComponent, ref, onMounted } from '@/uni_modules/lime-shared/vue';
|
||||
import { addUnit } from '@/uni_modules/lime-shared/addUnit';
|
||||
import { isObject } from '@/uni_modules/lime-shared/isObject';
|
||||
import { pathToBase64 } from '@/uni_modules/lime-shared/pathToBase64';
|
||||
import IconProps from './props';
|
||||
const name = 'l-icon';
|
||||
export default defineComponent({
|
||||
name,
|
||||
externalClasses: ['l-class'],
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
},
|
||||
props: IconProps,
|
||||
emits: ['click'],
|
||||
setup(props, { emit }) {
|
||||
const { $iconsHost, $iconCollections } = uni as any
|
||||
const IconifyURL = 'https://api.iconify.design/'
|
||||
const hasImage = ref(false)
|
||||
const iconUrl = ref('')
|
||||
const hasHost = computed(() => `${props.name}`.indexOf('/') !== -1);
|
||||
const isIconify = computed(() => !hasHost.value && `${props.name}`.includes(':'))
|
||||
const collectionIcon = computed(() => isObject($iconCollections) && $iconCollections[props.name])
|
||||
const isImage = computed(() => hasHost.value || /\.(.+)$/i.test(props.name) || collectionIcon.value && collectionIcon.value.length > 5 || hasImage.value);
|
||||
const classes = computed(() => {
|
||||
const { prefix } = props
|
||||
const iconPrefix = prefix || name
|
||||
const iconName = `${iconPrefix}-${props.name}`
|
||||
return {
|
||||
[iconPrefix]: !isImage.value && prefix,
|
||||
[iconName]: !isImage.value,
|
||||
[`${name}--image`]: isImage.value,
|
||||
[`${name}--font`]: !isImage.value,
|
||||
[`is-inherit`]: isImage.value && (props.color || props.inherit)
|
||||
}
|
||||
})
|
||||
|
||||
const getIconUrl = computed(() => {
|
||||
if (hasHost.value) {
|
||||
return props.name
|
||||
}
|
||||
if (/\.(.+)$/i.test(props.name)) {
|
||||
return `${$iconsHost}${props.name}`
|
||||
}
|
||||
if (collectionIcon.value && collectionIcon.value.length > 4) {
|
||||
return collectionIcon.value
|
||||
}
|
||||
return iconUrl.value
|
||||
})
|
||||
const styles = computed(() => {
|
||||
return {
|
||||
'font-size': addUnit(props.size),
|
||||
'color': props.color,
|
||||
'--l-icon': getIconUrl.value ? `url("${getIconUrl.value}")` : ''
|
||||
}
|
||||
})
|
||||
const imageLoad = () => {
|
||||
hasImage.value = true
|
||||
}
|
||||
const imageError = () => {
|
||||
hasImage.value = false
|
||||
if(isIconify.value && iconUrl.value && !iconUrl.value.includes(IconifyURL)) {
|
||||
const name = `${props.name}.svg`.replace(/:/g, '/')
|
||||
iconUrl.value = `${IconifyURL}${name}`
|
||||
}
|
||||
}
|
||||
const onClick = () => emit('click');
|
||||
const addSlash = (string: string) => {
|
||||
if (string.charAt(string.length - 1) !== '/') {
|
||||
string += '/';
|
||||
}
|
||||
return string;
|
||||
}
|
||||
const getBase64 = () => {
|
||||
if(isIconify.value) {
|
||||
const name = `${props.name}.svg`.replace(/:/g, '/')
|
||||
// 本地的SVG需要转成BASE64
|
||||
if(!hasHost.value && $iconsHost && $iconsHost.startsWith("/static")) {
|
||||
const url = `${addSlash($iconsHost)}${name}`
|
||||
// #ifdef MP
|
||||
if(!/^(?:https?|ftp):\/\/|^\/\//i.test(url)) {
|
||||
pathToBase64(url).then(base64 => {
|
||||
iconUrl.value = base64
|
||||
})
|
||||
} else {
|
||||
iconUrl.value = url
|
||||
}
|
||||
// #endif
|
||||
// #ifndef MP
|
||||
iconUrl.value = url
|
||||
// #endif
|
||||
} else {
|
||||
iconUrl.value = `${IconifyURL}${name}`
|
||||
}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
onMounted(getBase64)
|
||||
return {
|
||||
classes,
|
||||
styles,
|
||||
isImage,
|
||||
onClick,
|
||||
props,
|
||||
iconUrl,
|
||||
imageLoad,
|
||||
imageError
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
export const ariaProps = {
|
||||
ariaHidden: Boolean,
|
||||
ariaRole: String,
|
||||
ariaLabel: String,
|
||||
ariaLabelledby: String,
|
||||
ariaDescribedby: String,
|
||||
ariaBusy: Boolean,
|
||||
lStyle: String
|
||||
}
|
||||
|
||||
export default {
|
||||
...ariaProps,
|
||||
// lClass: String,
|
||||
name: String,
|
||||
color: String,
|
||||
size: String,
|
||||
prefix: String,
|
||||
// type: String,
|
||||
inherit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// lStyle: String,
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
<template>
|
||||
<demo-block title="图标" type="ultra">
|
||||
<demo-block title="自定义字体图标" type="large">
|
||||
<view class="gird">
|
||||
<view class="gird-item" v-for="item in customList" :key="item">
|
||||
<l-icon prefix="custom" :name="item" @click="onClick(item)"></l-icon>
|
||||
<text>{{item}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
<demo-block title="使用图片URL" type="large">
|
||||
<view class="gird">
|
||||
<view class="gird-item" v-for="item in imageList" :key="item">
|
||||
<l-icon :key="item" :name="item" @click="onClick(item)"></l-icon>
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
<demo-block title="iconify" type="large">
|
||||
<view class="gird" style="color: blue">
|
||||
<view class="gird-item">
|
||||
<l-icon name="uil:12-plus" :inherit="false"></l-icon>
|
||||
<!-- <text>uil:12-plus</text> -->
|
||||
</view>
|
||||
<view class="gird-item">
|
||||
<l-icon name="icon-park-outline:abdominal"></l-icon>
|
||||
<!-- <text>icon-park-outline:abdominal</text> -->
|
||||
</view>
|
||||
<view class="gird-item">
|
||||
<l-icon name="icon-park-outline:acoustic"></l-icon>
|
||||
<!-- <text>icon-park-outline:acoustic</text> -->
|
||||
</view>
|
||||
<view class="gird-item">
|
||||
<!-- <l-icon name="ri:aliens-fill"></l-icon>
|
||||
<l-icon name="uil:android"></l-icon> -->
|
||||
<l-icon name="uil:android-alt"></l-icon>
|
||||
<!-- <l-icon name="ri:alarm-fill"></l-icon> -->
|
||||
<!-- <text>ri:aliens-fill</text> -->
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</demo-block>
|
||||
</demo-block>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
customList: [
|
||||
'image-fill',
|
||||
'image-fail-fill',
|
||||
'close-circle-fill',
|
||||
'close',
|
||||
],
|
||||
imageList: [
|
||||
'https://tdesign.gtimg.com/miniprogram/images/icon1.png',
|
||||
'https://tdesign.gtimg.com/miniprogram/images/icon2.png',
|
||||
'https://fastly.jsdelivr.net/npm/@vant/assets/icon-demo.png',
|
||||
"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.999 2.999h12v-1h-12v1zM3.377 10.23l4.11-4.035v8.649h1.01V6.19l4.18 4.077.715-.7-5.05-4.926a.5.5 0 0 0-.7.001L2.66 9.532l.716.697z' fill='%23000' fill-opacity='.9'/%3E%3C/svg%3E"
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick(name: string) {
|
||||
// #ifndef UNI-APP-X
|
||||
uni.setClipboardData({
|
||||
data: name,
|
||||
success: function() {
|
||||
uni.showToast({
|
||||
title: name
|
||||
})
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
// import {defineComponent} from '@/uni_modules/lime-shared/vue';
|
||||
// export default defineComponent({
|
||||
// setup() {
|
||||
// const customList = [
|
||||
// 'image-fill',
|
||||
// 'image-fail-fill',
|
||||
// 'close-circle-fill',
|
||||
// 'close',
|
||||
// ]
|
||||
// const imageList = [
|
||||
// 'https://tdesign.gtimg.com/miniprogram/images/icon1.png',
|
||||
// 'https://tdesign.gtimg.com/miniprogram/images/icon2.png',
|
||||
// 'https://fastly.jsdelivr.net/npm/@vant/assets/icon-demo.png',
|
||||
// "data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.999 2.999h12v-1h-12v1zM3.377 10.23l4.11-4.035v8.649h1.01V6.19l4.18 4.077.715-.7-5.05-4.926a.5.5 0 0 0-.7.001L2.66 9.532l.716.697z' fill='%23000' fill-opacity='.9'/%3E%3C/svg%3E"
|
||||
// ]
|
||||
// const onClick = (name) => {
|
||||
// uni.setClipboardData({
|
||||
// data: name,
|
||||
// success: function() {
|
||||
// uni.showToast({
|
||||
// title: name
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// return {
|
||||
// onClick,
|
||||
// imageList,
|
||||
// customList
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
</script>
|
||||
<style lang="scss" >
|
||||
.icon-demo {
|
||||
font-size: 52rpx;
|
||||
}
|
||||
|
||||
.gird {
|
||||
font-size: 52rpx;
|
||||
/* #ifndef APP-NVUE || UNI-APP-X */
|
||||
display: grid;
|
||||
// gap: 20rpx;
|
||||
grid-row-gap: 40rpx;
|
||||
grid-template-columns: repeat(4,1fr);
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE || UNI-APP-X */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
/* #endif */
|
||||
&-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
text {
|
||||
padding-top: 10rpx;
|
||||
font-size: 22rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 以下为自定义图标
|
||||
// 小程序只在全局设置才生效
|
||||
/* CDN 服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
|
||||
@font-face {
|
||||
font-family: 'iconfont'; /* Project id 2624395 */
|
||||
src: url('data:font/ttf;charset=utf-8;base64,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Y2E4OwHneTx5eTx5eTx5eTwAAAAAAwAA/9UDqwMrABQAKQA1AAAFIicmJyY0NzY3NjIXFhcWFAcGBwYnMjc2NzY0JyYnJiIHBgcGFBcWFxYTNxcHFwcnByc3JzcCAHRjYTg7OzhhY+hjYTg7OzhhY3RdT00uLi4uTU+6T00uLi4uTU9deTx5eTx5eTx5eTwrOzhhY+hjYTg7OzhhY+hjYTg7Vi4uTU+6T00uLi4uTU+6T00uLgGReTx5eTx5eTx5eTwAAAAAABIA3gABAAAAAAAAABUAAAABAAAAAAABAAgAFQABAAAAAAACAAcAHQABAAAAAAADAAgAJAABAAAAAAAEAAgALAABAAAAAAAFAAsANAABAAAAAAAGAAgAPwABAAAAAAAKACsARwABAAAAAAALABMAcgADAAEECQAAACoAhQADAAEECQABABAArwADAAEECQACAA4AvwADAAEECQADABAAzQADAAEECQAEABAA3QADAAEECQAFABYA7QADAAEECQAGABABAwADAAEECQAKAFYBEwADAAEECQALACYBaQpDcmVhdGVkIGJ5IGljb25mb250Cmljb25mb250UmVndWxhcmljb25mb250aWNvbmZvbnRWZXJzaW9uIDEuMGljb25mb250R2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20ACgBDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AAoAaQBjAG8AbgBmAG8AbgB0AFIAZQBnAHUAbABhAHIAaQBjAG8AbgBmAG8AbgB0AGkAYwBvAG4AZgBvAG4AdABWAGUAcgBzAGkAbwBuACAAMQAuADAAaQBjAG8AbgBmAG8AbgB0AEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AaAB0AHQAcAA6AC8ALwBmAG8AbgB0AGUAbABsAG8ALgBjAG8AbQAAAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4BAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPAAppbWFnZS1maWxsD2ltYWdlLWZhaWwtZmlsbBFhcnJvdy1sZWZ0LXMtZmlsbBFhcnJvdy1sZWZ0LXMtbGluZQ9hcnJvdy11cC1zLWZpbGwPYXJyb3ctdXAtcy1saW5lEmFycm93LXJpZ2h0LXMtbGluZRJhcnJvdy1yaWdodC1zLWZpbGwRYXJyb3ctZG93bi1zLWxpbmURYXJyb3ctZG93bi1zLWZpbGwKY2xvc2UtZmlsbBFjbG9zZS1jaXJjbGUtZmlsbBFjbG9zZS1jaXJjbGUtbGluZQAAAAAA') format('truetype');
|
||||
}
|
||||
|
||||
.custom {
|
||||
font-family: 'iconfont' !important;
|
||||
}
|
||||
.custom-image-fill::before{
|
||||
content: '\e771';
|
||||
}
|
||||
.custom-image-fail-fill::before{
|
||||
content: '\e772';
|
||||
}
|
||||
.custom-close-circle-fill::before{
|
||||
content: '\e766';
|
||||
}
|
||||
.custom-close::before{
|
||||
content: '\e768';
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
const { generate } = require('./utils/generate.js');
|
||||
generate()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// lime.config.js
|
||||
module.exports = {
|
||||
// 输入的文件目录,自有的SVG,如果没有则不需要
|
||||
input: {
|
||||
prefix: "my-icons",
|
||||
dir: '/static/svg',
|
||||
},
|
||||
// 输出的配置
|
||||
output: {
|
||||
// 输出的文件目录
|
||||
dir: '/static/icon',
|
||||
// 输出的文件的格式,如果是JSON则是一个图标合集
|
||||
// file: 'icons.json',
|
||||
// 如果是SVG则是每个图标做为单独的文件
|
||||
file: '*.svg',
|
||||
},
|
||||
icons: [
|
||||
'el:address-book',
|
||||
'uil:12-plus',
|
||||
'icon-park-outline:abdominal',
|
||||
'icon-park-outline:acoustic'
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
{
|
||||
"id": "lime-icon",
|
||||
"displayName": "lime-icon 图标 iconify 图标集合",
|
||||
"version": "0.0.3",
|
||||
"description": "基于uniapp vue3 实现的图标插件,方便快捷的使用iconify图标集合。超过150,000个开源矢量图标。按需加载,仅在H5\\微信小程序测试",
|
||||
"keywords": [
|
||||
"icon",
|
||||
"iconify",
|
||||
"图标集合",
|
||||
"按需加载"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.98"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
"lime-shared"
|
||||
],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
const { readFileSync, existsSync } = require('fs');
|
||||
const path = require('path');
|
||||
const {generate} = require('./utils/generate')
|
||||
|
||||
// 插件的名称
|
||||
const pluginName = 'lime-icon-plugin';
|
||||
|
||||
// 要监听的组件的名称
|
||||
const targetComponent = 'l-icon';
|
||||
|
||||
function parseAttributes(attributesStr) {
|
||||
if (!attributesStr.includes("'")) {
|
||||
return [attributesStr]
|
||||
}
|
||||
const regex = /'([^']+)'/g;
|
||||
const matches = attributesStr.match(regex);
|
||||
if (matches) {
|
||||
const targetContent = matches.map(item => item.replace(/'/g, ''));
|
||||
return targetContent
|
||||
} else {
|
||||
return [attributesStr]
|
||||
}
|
||||
}
|
||||
|
||||
function extractAttributes(content) {
|
||||
const regex = /<l-icon\s*[^>]*(:?)name=["]([^"]+)["][^>]*>/g; // /<l-icon\s+(.*?)\s*\/?>/g //<l-icon\s+([^>]+)\s*\/?>/g;
|
||||
let attributes = [];
|
||||
const attributesSet = new Set(attributes);
|
||||
let match;
|
||||
while ((match = regex.exec(content)) !== null) {
|
||||
const attributesStr = match[2];
|
||||
const attributesList = parseAttributes(attributesStr);
|
||||
for (const attribute of attributesList) {
|
||||
attributesSet.add(attribute); // 添加新属性到Set中
|
||||
}
|
||||
}
|
||||
attributes = [...attributesSet];
|
||||
return attributes;
|
||||
}
|
||||
// 遍历每个文件并检查是否使用了目标组件
|
||||
let iconCollections = {}
|
||||
let files = {}
|
||||
let timer = null
|
||||
function processFile(file, options) {
|
||||
const filePath = path.resolve(file);
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
|
||||
// 检查文件是否包含目标组件
|
||||
if (content.includes(targetComponent) && !file.includes('l-icon.vue') && files[file] !== content) {
|
||||
const icons = extractAttributes(content)
|
||||
if(icons && icons.length) {
|
||||
files[file] = content
|
||||
iconCollections[file] = icons
|
||||
}
|
||||
Object.values(iconCollections).forEach(icons => {
|
||||
if(options.icons) {
|
||||
options.icons = options.icons.concat(icons);
|
||||
} else {
|
||||
options.icons = icons
|
||||
}
|
||||
})
|
||||
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
options.icons = Array.from(new Set(options.icons))
|
||||
generate(options)
|
||||
},500)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 插件的钩子函数
|
||||
function vitePlugin(options = {}) {
|
||||
const {useInDevelopment = false} = options
|
||||
const isDev = process.env.NODE_ENV === 'development'
|
||||
return {
|
||||
name: pluginName,
|
||||
transform(code, id) {
|
||||
if (id.endsWith('.vue') && (useInDevelopment && isDev || !useInDevelopment && !isDev)) {
|
||||
// 处理Vue文件
|
||||
processFile(id, options);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = vitePlugin;
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
# lime-icon 图标
|
||||
- 基于uniapp vue3 实现的图标插件,方便快捷的使用[iconify](https://iconify.design/)图标集合。超过150,000个开源矢量图标。
|
||||
- 当前仅为测试阶段,欢迎提出你的建议
|
||||
|
||||
## 使用
|
||||
### 基础使用
|
||||
到 [iconify](https://icon-sets.iconify.design/) 网站找到需要的图标,通过 `name` 属性来指定需要使用的图标
|
||||

|
||||

|
||||
|
||||
```html
|
||||
<l-icon name="ri:aliens-fill" />
|
||||
```
|
||||
|
||||
### 使用图标URL
|
||||
```html
|
||||
<l-icon name="https://fastly.jsdelivr.net/npm/@vant/assets/icon-demo.png"></l-icon>
|
||||
```
|
||||
|
||||
### 图标颜色
|
||||
通过 `color` 属性来设置图标的颜色。
|
||||
|
||||
```html
|
||||
<l-icon name="ri:aliens-fill" color="#1989fa" />
|
||||
<l-icon name="icon-park-outline:acoustic" color="#ee0a24" />
|
||||
```
|
||||
|
||||
### 图标大小
|
||||
|
||||
通过 `size` 属性来设置图标的尺寸大小,可以指定任意 CSS 单位。
|
||||
|
||||
```html
|
||||
<!-- 不指定单位,默认使用 px -->
|
||||
<l-icon name="ri:aliens-fill" size="40" />
|
||||
<!-- 指定使用 rem 单位 -->
|
||||
<l-icon name="ri:aliens-fill" size="34rpx" />
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 自定义字体图标
|
||||
- 如果需要自定义自己的 字体图标,可以引入 iconfont 对应的字体文件和 CSS 文件,之后就可以在 Icon 组件中直接使用
|
||||
- 样式必须是放在页面或App.vue
|
||||
|
||||
```css
|
||||
@font-face {
|
||||
font-family: 'iconfont'; /* Project id 2624395 */
|
||||
src: url('data:font/ttf;charset=utf-8;base64,AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzI+O0pCAAABjAAAAGBjbWFw6NhtkAAAAiQAAAIYZ2x5ZuZYvOIAAARcAAADcGhlYWQdInJhAAAA4AAAADZoaGVhB4IDjwAAALwAAAAkaG10eDgAAAAAAAHsAAAAOGxvY2EGNgVIAAAEPAAAAB5tYXhwARwAQgAAARgAAAAgbmFtZT5U/n0AAAfMAAACbXBvc3T99mzoAAAKPAAAARkAAQAAA4D/gAAABAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAA4AAQAAAAEAAMHRJwVfDzz1AAsEAAAAAADdAZcyAAAAAN0BlzIAAP/VBAADKwAAAAgAAgAAAAAAAAABAAAADgA2AAQAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAQEAAH0AAUAAAKJAswAAACPAokCzAAAAesAMgEIAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAwOdm53IDgP+AAFwD3ACAAAAAAQAAAAAAAAAAAAAAAAACBAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAAAAAFAAAAAwAAACwAAAAEAAABbAABAAAAAABmAAMAAQAAACwAAwAKAAABbAAEADoAAAAEAAQAAQAA53L//wAA52b//wAAAAEABAAAAAwADQALAAMABAAFAAYABwAIAAkACgABAAIAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAKwAAAAAAAAADQAA52YAAOdmAAAADAAA52cAAOdnAAAADQAA52gAAOdoAAAACwAA52kAAOdpAAAAAwAA52oAAOdqAAAABAAA52sAAOdrAAAABQAA52wAAOdsAAAABgAA520AAOdtAAAABwAA524AAOduAAAACAAA528AAOdvAAAACQAA53AAAOdwAAAACgAA53EAAOdxAAAAAQAA53IAAOdyAAAAAgAAAAAAOACEAJIApgC0AMgA3ADqAP4BDAEmAWABuAAAAAMAAP//A6sDAQAHABcAIAAAASERATYyHwEBNDYzITIWFREUBiMhIiY1ASImNDYyFhQGA1X9VgGMDSMM4v0AGRIDABIZGRL9ABIZAQAjMjJHMjICq/2qAY0MDOIB1hEZGRH9VBEZGREBgTJGMjJGMgAEAAD//wOrAwEADwAQABkALQAAJSc3AREhNyEiBhURFBYzIQMjFBYyNjQmIgYlIQchEScmIg8CFwchMjY1ETQmAmLAJ/7iAWoW/lUTGBkSAaLNVTJHMjJHMgKA/usWAQDiDSINFS/JVgEaERoYsx6r/tkCVlUXFP1WERoCACMyMkYyMt1V/lXiDQ0VzR7iGBMCqhQXAAAAAAEAAAAAAlYCgAACAAAJAREBVQEAAYABAP4AAAABAAAAAAKiApAABQAAARcHCQEXAc7TPP7wARA8AYDTPQEQARA9AAAAAQAAAAADAAIrAAIAAAkBIQIAAQD+AAIr/wAAAAEAAAAAAxACKwAFAAABBycJAQcCANM9ARABED0BstM8ARD+8DwAAAABAAAAAAKrApAABQAAASc3CQEnAjLTPAEQ/vA8AYDTPf7w/vA9AAAAAQAAAAACqwKAAAIAAAkBEQKr/wABgP8AAgAAAAEAAAAAAxACIgAFAAABNxcJATcCANM9/vD+8D0BTtM8/vABEDwAAAABAAAAAAMAAdYAAgAAJQEhAgD/AAIA1QEAAAAAAQAAAAADEAKQAAsAAAE3FwcXBycHJzcnNwIA0z3U1D3T0z3U1D0BvNQ909M91NQ909M9AAIAAP/VA6sDKwAUACAAAAUiJyYnJjQ3Njc2MhcWFxYUBwYHBgMnBxcHFzcXNyc3JwIAdGNhODs7OGFj6GNhODs7OGFjdHk8eXk8eXk8eXk8Kzs4YWPoY2E4Ozs4YWPoY2E4OwHneTx5eTx5eTx5eTwAAAAAAwAA/9UDqwMrABQAKQA1AAAFIicmJyY0NzY3NjIXFhcWFAcGBwYnMjc2NzY0JyYnJiIHBgcGFBcWFxYTNxcHFwcnByc3JzcCAHRjYTg7OzhhY+hjYTg7OzhhY3RdT00uLi4uTU+6T00uLi4uTU9deTx5eTx5eTx5eTwrOzhhY+hjYTg7OzhhY+hjYTg7Vi4uTU+6T00uLi4uTU+6T00uLgGReTx5eTx5eTx5eTwAAAAAABIA3gABAAAAAAAAABUAAAABAAAAAAABAAgAFQABAAAAAAACAAcAHQABAAAAAAADAAgAJAABAAAAAAAEAAgALAABAAAAAAAFAAsANAABAAAAAAAGAAgAPwABAAAAAAAKACsARwABAAAAAAALABMAcgADAAEECQAAACoAhQADAAEECQABABAArwADAAEECQACAA4AvwADAAEECQADABAAzQADAAEECQAEABAA3QADAAEECQAFABYA7QADAAEECQAGABABAwADAAEECQAKAFYBEwADAAEECQALACYBaQpDcmVhdGVkIGJ5IGljb25mb250Cmljb25mb250UmVndWxhcmljb25mb250aWNvbmZvbnRWZXJzaW9uIDEuMGljb25mb250R2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20ACgBDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AAoAaQBjAG8AbgBmAG8AbgB0AFIAZQBnAHUAbABhAHIAaQBjAG8AbgBmAG8AbgB0AGkAYwBvAG4AZgBvAG4AdABWAGUAcgBzAGkAbwBuACAAMQAuADAAaQBjAG8AbgBmAG8AbgB0AEcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAAcwB2AGcAMgB0AHQAZgAgAGYAcgBvAG0AIABGAG8AbgB0AGUAbABsAG8AIABwAHIAbwBqAGUAYwB0AC4AaAB0AHQAcAA6AC8ALwBmAG8AbgB0AGUAbABsAG8ALgBjAG8AbQAAAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4BAgEDAQQBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPAAppbWFnZS1maWxsD2ltYWdlLWZhaWwtZmlsbBFhcnJvdy1sZWZ0LXMtZmlsbBFhcnJvdy1sZWZ0LXMtbGluZQ9hcnJvdy11cC1zLWZpbGwPYXJyb3ctdXAtcy1saW5lEmFycm93LXJpZ2h0LXMtbGluZRJhcnJvdy1yaWdodC1zLWZpbGwRYXJyb3ctZG93bi1zLWxpbmURYXJyb3ctZG93bi1zLWZpbGwKY2xvc2UtZmlsbBFjbG9zZS1jaXJjbGUtZmlsbBFjbG9zZS1jaXJjbGUtbGluZQAAAAAA') format('truetype');
|
||||
}
|
||||
.custom {
|
||||
font-family: 'iconfont' !important;
|
||||
}
|
||||
.custom-image-fill::before{
|
||||
content: '\e771';
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- 通过 prefix 指定类名为 custom -->
|
||||
<l-icon prefix="custom" name="image-fill"></l-icon>
|
||||
```
|
||||
|
||||
|
||||
## 私有化
|
||||
默认会使用`iconify`的API,如果你想私有化可按以下步骤来
|
||||
### 第一步 安装
|
||||
|
||||
```cmd
|
||||
yarn add @iconify/json @iconify/tools @iconify/utils
|
||||
```
|
||||
### 第二步 配置
|
||||
#### 1、手动下载
|
||||
- 需要在根目录新建一个lime.config.js文件
|
||||
|
||||
```
|
||||
// 在根目录新建一个lime.config.js文件
|
||||
// lime.config.js
|
||||
module.exports = {
|
||||
// 输入的文件目录,自有的SVG,如果没有则不需要
|
||||
input: {
|
||||
prefix: "my-icons",
|
||||
dir: '/static/svg',
|
||||
},
|
||||
// 输出的配置
|
||||
output: {
|
||||
// 输出的文件目录
|
||||
dir: '/static/icons',
|
||||
// 输出的文件的格式,如果是JSON则是一个图标合集
|
||||
// file: 'icons.json',
|
||||
// 如果是SVG则是每个图标做为单独的文件
|
||||
file: '*.svg',
|
||||
},
|
||||
// 指定使用的图标
|
||||
icons: [
|
||||
'el:address-book',
|
||||
'uil:12-plus',
|
||||
'icon-park-outline:abdominal',
|
||||
'icon-park-outline:acoustic'
|
||||
]
|
||||
}
|
||||
```
|
||||
在终端执行脚本
|
||||
```
|
||||
node ./uni_modules/lime-icon/generate-icons.js
|
||||
```
|
||||
|
||||
#### 2、自动引入
|
||||
如果使用的是vue3,通过配置 **vite.config.js**达到自动引入
|
||||
|
||||
```js
|
||||
import uni from '@dcloudio/vite-plugin-uni';
|
||||
import limeIcon from './uni_modules/lime-icon/plugin';
|
||||
import path from 'path'
|
||||
export default defineConfig({
|
||||
plugins: [uni(), limeIcon({
|
||||
// 输出的配置
|
||||
output: {
|
||||
// 输出的文件目录
|
||||
dir: path.join(__dirname, '/static/icons'),
|
||||
// 输出的文件的格式,如果是JSON则是生成一个图标合集, 例如: /static/icons/icons.json
|
||||
// file: 'icons.json',
|
||||
// 如果是SVG则是每个图标做为单独的文件 例如: /static/icons/xx/xxx.svg
|
||||
file: '*.svg',
|
||||
},
|
||||
// 可选
|
||||
icons: []
|
||||
})]
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### 第三步 挂载图标地址
|
||||
|
||||
```js
|
||||
// main.js
|
||||
// 如果配置的是json则引入json
|
||||
import icons from './static/icons/icons.json'
|
||||
uni.$iconCollections = icons;
|
||||
// 如果配置的是单个svg则指定目录,后期可上传到后端,不占用本地空间
|
||||
uni.$iconsHost = '/static/icons/';
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- | ------------ |
|
||||
| name | 图标名称 | <em>string</em> | `` |
|
||||
| color | 颜色 | <em>string</em> | `` |
|
||||
| size | 尺寸 | <em>string</em> | `square` |
|
||||
| prefix | 字体图标前缀 | <em>string</em> | `` |
|
||||
| inherit | 是否继承颜色 | <em>boolean</em> | `true` |
|
||||
|
||||
### Events
|
||||
| 参数 | 说明 | 参数 |
|
||||
| --------------------------| ------------------------------------------------------------ | ---------------- |
|
||||
| click | 点击 | |
|
||||
|
||||
|
||||
## 打赏
|
||||
|
||||
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||

|
||||

|
||||
|
|
@ -0,0 +1,120 @@
|
|||
const path = require('path');
|
||||
const fs = require("fs");
|
||||
const rootPath = process.cwd(); // 获取根目录
|
||||
const { importDirectory, blankIconSet } = require("@iconify/tools");
|
||||
const { locate } = require('@iconify/json');
|
||||
const { getIconData } = require('@iconify/utils');
|
||||
const { encodeSvg, saveFile, customOptions, deleteDirectory } = require('./index.js')
|
||||
async function fetchIconsData(icons) {
|
||||
const collections = {}
|
||||
for (const iconName of icons) {
|
||||
const [collectionName, iconNameWithoutPrefix] = iconName.split(':');
|
||||
const filename = locate(collectionName)
|
||||
if(!fs.existsSync(filename)) {
|
||||
continue
|
||||
}
|
||||
const icons = JSON.parse(fs.readFileSync(filename, 'utf8'))
|
||||
if(!icons) {
|
||||
continue
|
||||
}
|
||||
if(collectionName && iconNameWithoutPrefix) {
|
||||
const iconData = getIconData(icons, iconNameWithoutPrefix);
|
||||
if(iconData) {
|
||||
if(!collections[collectionName]) {
|
||||
collections[collectionName] = blankIconSet(collectionName);
|
||||
}
|
||||
collections[collectionName].setIcon(iconNameWithoutPrefix, iconData);
|
||||
} else {
|
||||
console.log(`Icon '${iconName}' not found in '${collectionName}' collection.`)
|
||||
}
|
||||
} else if(collectionName) {
|
||||
if(!collections[collectionName]) {
|
||||
collections[collectionName] = blankIconSet(collectionName)
|
||||
}
|
||||
Object.keys(icons.icons).forEach(iconName => {
|
||||
const iconData = getIconData(icons, iconName)
|
||||
if(iconData) {
|
||||
collections[collectionName].setIcon(iconName, iconData)
|
||||
} else {
|
||||
console.log(`Icon '${iconName}' not found in '${collectionName}' collection.`)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return collections;
|
||||
}
|
||||
|
||||
async function generate(config){
|
||||
try {
|
||||
if(!config) {
|
||||
// 从配置文件中读取选项
|
||||
const rootConfigPath = path.join(rootPath, 'lime.config.js');
|
||||
let configPath = ''
|
||||
if(fs.existsSync(rootConfigPath)) {
|
||||
configPath = rootConfigPath
|
||||
} else {
|
||||
configPath = path.dirname(__filename) + '/lime.config.js'; // 配置文件路径
|
||||
}
|
||||
|
||||
const configFile = fs.readFileSync(configPath, 'utf8');
|
||||
config = eval(`(${configFile})`);
|
||||
}
|
||||
|
||||
// 根据配置文件中的字段设置选项
|
||||
const options = {
|
||||
input: Object.assign({}, customOptions, config.input || {}), // 输入的文件目录
|
||||
output: {
|
||||
dir: config.output.dir || '/static', // 输出的文件目录
|
||||
file: config.output.file || 'icons.json', // 输出的文件的格式,默认为 JSON
|
||||
},
|
||||
icons: config.icons || [], // 图标名称列表
|
||||
};
|
||||
|
||||
// 先删除原来的
|
||||
deleteDirectory(options.output.dir)
|
||||
// 处理输入目录的逻辑
|
||||
if (config.input.dir.startsWith('/')) {
|
||||
options.input.dir = path.join(rootPath, config.input.dir);
|
||||
} else if (config.input.dir.startsWith('./')) {
|
||||
options.input.dir = path.join(__dirname, config.input.dir.slice(2));
|
||||
}
|
||||
let iconCollections = {}
|
||||
// 异步地从目录中导入图标
|
||||
if(fs.existsSync(options.input.dir)) {
|
||||
const iconSet = await importDirectory(options.input.dir, options.input);
|
||||
// 导出为 JSON 文件
|
||||
iconCollections[options.input.prefix] = iconSet
|
||||
}
|
||||
|
||||
// 获取指定图标的数据
|
||||
if(options.icons.length) {
|
||||
const iconCollection = await fetchIconsData(options.icons);
|
||||
Object.assign(iconCollections, iconCollection)
|
||||
}
|
||||
|
||||
if(/\.json$/i.test(options.output.file)) {
|
||||
const collections = {}
|
||||
Object.values(iconCollections).forEach((iconSet) => {
|
||||
|
||||
iconSet.forEach(iconName => {
|
||||
// 将 SVG 转换为 Data URL
|
||||
collections[iconSet.prefix + ':' + iconName] = `data:image/svg+xml;utf8,${encodeSvg(iconSet.toString(iconName))}`
|
||||
})
|
||||
})
|
||||
await saveFile(`${options.output.dir}/${options.output.file}`, JSON.stringify(collections))
|
||||
} else {
|
||||
Object.values(iconCollections).forEach((iconSet) => {
|
||||
iconSet.forEach(async iconName => {
|
||||
await saveFile(`${options.output.dir}/${iconSet.prefix}/${iconName}.svg`, iconSet.toString(iconName))
|
||||
})
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("导出图标集为 JSON 文件时出错:", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
generate
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
const fs = require("fs");
|
||||
const glob = require('glob');
|
||||
const path = require("path");
|
||||
const rootPath = process.cwd(); // 获取根目录
|
||||
// https://bl.ocks.org/jennyknuth/222825e315d45a738ed9d6e04c7a88d0
|
||||
function encodeSvg(svg) {
|
||||
return svg
|
||||
.replace(
|
||||
"<svg",
|
||||
~svg.indexOf("xmlns") ? "<svg" : '<svg xmlns="http://www.w3.org/2000/svg"'
|
||||
)
|
||||
.replace(/"/g, "'")
|
||||
.replace(/%/g, "%25")
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/{/g, "%7B")
|
||||
.replace(/}/g, "%7D")
|
||||
.replace(/</g, "%3C")
|
||||
.replace(/>/g, "%3E");
|
||||
}
|
||||
|
||||
|
||||
function isDirectoryEmpty(path) {
|
||||
const files = fs.readdirSync(path);
|
||||
return files.length === 0;
|
||||
}
|
||||
function deleteFolderBFS(folderPath) {
|
||||
const outputPath = /^\.|\/|\\/.test(folderPath) ? path.join(rootPath, folderPath): folderPath
|
||||
if(!fs.existsSync(outputPath)) {
|
||||
return
|
||||
}
|
||||
const queue = [outputPath];
|
||||
while (queue.length > 0) {
|
||||
const currentPath = queue.shift();
|
||||
const currentStats = fs.statSync(currentPath);
|
||||
|
||||
if (currentStats.isDirectory()) {
|
||||
const files = fs.readdirSync(currentPath);
|
||||
for (const file of files) {
|
||||
const filePath = path.join(currentPath, file);
|
||||
const fileStats = fs.statSync(filePath);
|
||||
if (fileStats.isDirectory()) {
|
||||
queue.push(filePath);
|
||||
} else {
|
||||
fs.unlinkSync(filePath); // 删除文件
|
||||
}
|
||||
}
|
||||
if(isDirectoryEmpty(currentPath)) {
|
||||
fs.rmdirSync(currentPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保存
|
||||
async function saveFile(file, data) {
|
||||
const outputPath = /^(\.|\/|\\)/.test(file) ? path.join(rootPath, file) : file;
|
||||
const outputDir = path.dirname(outputPath);
|
||||
try {
|
||||
// 创建文件夹
|
||||
await fs.promises.mkdir(outputDir, {
|
||||
recursive: true
|
||||
});
|
||||
|
||||
// 使用 Promise 进行写入文件操作
|
||||
await fs.promises.writeFile(outputPath, data, "utf8");
|
||||
// console.log(`成功保存文件:${outputPath}`);
|
||||
} catch (error) {
|
||||
console.error("保存文件时出错:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 可选的选项对象
|
||||
const customOptions = {
|
||||
prefix: "l", // 为图标集设置前缀
|
||||
includeSubDirs: true, // 启用扫描子目录中的文件(默认启用)
|
||||
keyword: (fileName, defaultKeyword, iconSet) => {
|
||||
// 根据文件名自定义关键字生成
|
||||
// 返回关键字或 undefined 以跳过该文件
|
||||
return defaultKeyword;
|
||||
},
|
||||
ignoreImportErrors: true, // 禁用未成功导入图标时的错误抛出(默认启用)
|
||||
keepTitles: false, // 禁用在 SVG 中保留标题(默认禁用)
|
||||
};
|
||||
module.exports = {
|
||||
encodeSvg,
|
||||
saveFile,
|
||||
deleteDirectory: deleteFolderBFS,
|
||||
customOptions,
|
||||
};
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
## 1.9.6.4(2024-03-10)
|
||||
- fix: 修复代理ctx导致H5不能使用ctx.save
|
||||
## 1.9.6.3(2024-03-08)
|
||||
- fix: 修复支付宝真机无法使用的问题
|
||||
## 1.9.6.2(2024-02-22)
|
||||
- fix: 修复使用render函数报错的问题
|
||||
## 1.9.6.1(2023-12-22)
|
||||
- fix: 修复字节小程序非2d字体偏移
|
||||
- fix: 修复`canvasToTempFilePathSync`会触发两次的问题
|
||||
- fix: 修复`parser`图片没有宽度的问题
|
||||
## 1.9.6(2023-12-06)
|
||||
- fix: 修复背景图受padding影响
|
||||
- fix: 修复因字节报错改了代理实现导致微信报错
|
||||
- 1.9.5.8(2023-11-16)
|
||||
- fix: 修复margin问题
|
||||
- fix: 修复borderWidth问题
|
||||
- fix: 修复textBox问题
|
||||
- fix: 修复字节开发工具报`could not be cloned.`问题
|
||||
## 1.9.5.7(2023-07-27)
|
||||
- fix: 去掉多余的方法
|
||||
- chore: 更新文档,增加自定义字体说明
|
||||
## 1.9.5.6(2023-07-21)
|
||||
- feat: 有限的支持富文本
|
||||
- feat: H5和APP 增加 `hidpi` prop,主要用于大尺寸无法生成图片时用
|
||||
- fix: 修复 钉钉小程序 缺少 `measureText` 方法
|
||||
- chore: 由于微信小程序 pc 端的 canvas 2d 时不时抽风,故不使用canvas 2d
|
||||
## 1.9.5.5(2023-06-27)
|
||||
- fix: 修复把`emoji`表情字符拆分成多个字符的情况
|
||||
## 1.9.5.4(2023-06-05)
|
||||
- fix: 修复因`canvasToTempFilePathSync`监听导致重复调用
|
||||
## 1.9.5.3(2023-05-23)
|
||||
- fix: 因isPc错写成了isPC导致小程序PC不能生成图片
|
||||
## 1.9.5.2(2023-05-22)
|
||||
- feat: 删除多余文件
|
||||
## 1.9.5.1(2023-05-22)
|
||||
- fix: 修复 文字行数与`line-clamp`相同但不满一行时也加了省略号的问题
|
||||
## 1.9.5(2023-05-14)
|
||||
- feat: 增加 `text-indent` 和 `calc` 方法
|
||||
- feat: 优化 布局时间
|
||||
## 1.9.4.4(2023-04-15)
|
||||
- fix: 修复无法匹配负值
|
||||
- fix: 修复 Nvue IOS getImageInfo `useCORS` 为 undefined
|
||||
## 1.9.4.3(2023-04-01)
|
||||
- feat: 增加支持文字描边 `text-stroke: '5rpx #fff'`
|
||||
## 1.9.4.2(2023-03-30)
|
||||
- fix: 修复 支付宝小程序 isPC 在手机也为true的问题
|
||||
- feat: 由 微信开发工具 3060 版 无法获取图片尺寸,现 微信开发工具 3220 版 修复该问题,故还原上一版的获取图片方式。
|
||||
## 1.9.4.1(2023-03-28)
|
||||
- fix: 修复固定高度不正确问题
|
||||
## 1.9.4(2023-03-17)
|
||||
- fix: nvue ios getImageInfo缺少this报错
|
||||
- fix: pathType 非2d无效问题
|
||||
- fix: 修复 小米9se 可能会存在多次init 导致画面多次放大
|
||||
- fix: 修复 border 分开写 width style无效问题
|
||||
- fix: 修复 支付宝小程序IOS 再次进入不渲染的问题
|
||||
- fix: 修复 支付宝小程序安卓Zindex排序错乱问题
|
||||
- fix: 修复 微信开发工具 3060 版 无法获取图片的问题
|
||||
- feat: 把 for in 改为 forEach
|
||||
- feat: 增加 hidden
|
||||
- feat: 根节点 box-sizing 默认 `border-box`
|
||||
- feat: 增加支持 `vw` `wh`
|
||||
- chore: pathType 取消 默认值,因为字节开发工具不能显示
|
||||
- chore: 支付宝小程序开发工具不支持 生成图片 请以真机调试为准
|
||||
- bug: 企业微信 2.20.3无法使用
|
||||
## 1.9.3.5(2022-06-29)
|
||||
- feat: justifyContent 增加 `space-around`、`space-between`
|
||||
- feat: canvas 2d 也使用`getImageInfo`
|
||||
- fix: 修复 `text`的 `text-decoration`错位
|
||||
## 1.9.3.4(2022-06-20)
|
||||
- fix: 修复 因创建节点速度问题导致顺序出错。
|
||||
- fix: 修复 微信小程序 PC 无法显示本地图片
|
||||
- fix: 修复 flex-box 对齐问题
|
||||
- feat: 增加 `text-shadow`
|
||||
- feat: 重写 `text` 对齐方式
|
||||
- chore: 更新文档
|
||||
## 1.9.3.3(2022-06-17)
|
||||
- fix: 修复 支付宝小程序 canvas 2d 存在ctx.draw问题导致报错
|
||||
- fix: 修复 支付宝小程序 toDataURL 存在权限问题改用 `toTempFilePath`
|
||||
- fix: 修复 支付宝小程序 image size 问题导致 `objectFit` 无效
|
||||
## 1.9.3.2(2022-06-14)
|
||||
- fix: 修复 image 设置背景色不生效问题
|
||||
- fix: 修复 nvue 环境判断缺少参数问题
|
||||
## 1.9.3.1(2022-06-14)
|
||||
- fix: 修复 bottom 定位不对问题
|
||||
- fix: 修复 因小数导致计算出错换行问题
|
||||
- feat: 增加 `useCORS` h5端图片跨域 在设置请求头无效果后试一下设置这个值
|
||||
- chore: 更新文档
|
||||
## 1.9.3(2022-06-13)
|
||||
- feat: 增加 `zIndex`
|
||||
- feat: 增加 `flex-box` 该功能处于原始阶段,非常简陋。
|
||||
- tips: QQ小程序 vue3 不支持, 为 uni 官方BUG
|
||||
## 1.9.2.9(2022-06-10)
|
||||
- fix: 修复`text-align`及`margin`居中问题
|
||||
## 1.9.2.8(2022-06-10)
|
||||
- fix: 修复 Nvue `canvasToTempFilePathSync` 不生效问题
|
||||
## 1.9.2.7(2022-06-10)
|
||||
- fix: 修复 margin及padding的bug
|
||||
- fix: 修复 Nvue `isCanvasToTempFilePath` 不生效问题
|
||||
## 1.9.2.6(2022-06-09)
|
||||
- fix: 修复 Nvue 不显示
|
||||
- feat: 增加支持字体渐变
|
||||
```html
|
||||
<l-painter-text
|
||||
text="水调歌头\n明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间。"
|
||||
css="background: linear-gradient(,#ff971b 0%, #1989fa 100%); background-clip: text" />
|
||||
```
|
||||
## 1.9.2.5(2022-06-09)
|
||||
- chore: 更变获取父级宽度的设定
|
||||
- chore: `pathType` 在canvas 2d 默认为 `url`
|
||||
## 1.9.2.4(2022-06-08)
|
||||
- fix: 修复 `pathType` 不生效问题
|
||||
## 1.9.2.3(2022-06-08)
|
||||
- fix: 修复 `canvasToTempFilePath` 漏写 `success` 参数
|
||||
## 1.9.2.2(2022-06-07)
|
||||
- chore: 更新文档
|
||||
## 1.9.2.1(2022-06-07)
|
||||
- fix: 修复 vue3 赋值给this再传入导致image无法绘制
|
||||
- fix: 修复 `canvasToTempFilePathSync` 时机问题
|
||||
- feat: canvas 2d 更改图片生成方式 `toDataURL`
|
||||
## 1.9.2(2022-05-30)
|
||||
- fix: 修复 `canvasToTempFilePathSync` 在 vue3 下只生成一次
|
||||
## 1.9.1.7(2022-05-28)
|
||||
- fix: 修复 `qrcode`显示不全问题
|
||||
## 1.9.1.6(2022-05-28)
|
||||
- fix: 修复 `canvasToTempFilePathSync` 会重复多次问题
|
||||
- fix: 修复 `view` css `backgroundImage` 图片下载失败导致 子节点不渲染
|
||||
## 1.9.1.5(2022-05-27)
|
||||
- fix: 修正支付宝小程序 canvas 2d版本号 2.7.15
|
||||
## 1.9.1.4(2022-05-22)
|
||||
- fix: 修复字节小程序无法使用xml方式
|
||||
- fix: 修复字节小程序无法使用base64(非2D情况下工具上无法显示)
|
||||
- fix: 修复支付宝小程序 `canvasToTempFilePath` 报错
|
||||
## 1.9.1.3(2022-04-29)
|
||||
- fix: 修复vue3打包后uni对象为空后的报错
|
||||
## 1.9.1.2(2022-04-25)
|
||||
- fix: 删除多余文件
|
||||
## 1.9.1.1(2022-04-25)
|
||||
- fix: 修复图片不显示问题
|
||||
## 1.9.1(2022-04-12)
|
||||
- fix: 因四舍五入导致有些机型错位
|
||||
- fix: 修复无views报错
|
||||
- chore: nvue下因ios无法读取插件内static文件,改由下载方式
|
||||
## 1.9.0(2022-03-20)
|
||||
- fix: 因无法固定尺寸导致生成图片不全
|
||||
- fix: 特定情况下text判断无效
|
||||
- chore: 本地化APP Nvue webview
|
||||
## 1.8.9(2022-02-20)
|
||||
- fix: 修复 小程序下载最多10次并发的问题
|
||||
- fix: 修复 APP端无法获取本地图片
|
||||
- fix: 修复 APP Nvue端不执行问题
|
||||
- chore: 增加图片缓存机制
|
||||
## 1.8.8.8(2022-01-27)
|
||||
- fix: 修复 主动调用尺寸问题
|
||||
## 1.8.8.6(2022-01-26)
|
||||
- fix: 修复 nvue 下无宽度时获取父级宽度
|
||||
- fix: 修复 ios app 无法渲染问题
|
||||
## 1.8.8(2022-01-23)
|
||||
- fix: 修复 主动调用时无节点问题
|
||||
- fix: 修复 `box-shadow` 颜色问题
|
||||
- fix: 修复 `transform:rotate` 角度位置问题
|
||||
- feat: 增加 `overflow:hidden`
|
||||
## 1.8.7(2022-01-07)
|
||||
- fix: 修复 image 方向为 `right` 时原始宽高问题
|
||||
- feat: 支持 view 设置背景图 `background-image: url(xxx)`
|
||||
- chore: 去掉可选链
|
||||
## 1.8.6(2021-11-28)
|
||||
- feat: 支持`view`对`inline-block`的子集使用`text-align`
|
||||
## 1.8.5.5(2021-08-17)
|
||||
- chore: 更新文档,删除 replace
|
||||
- fix: 修复 text 值为 number时报错
|
||||
## 1.8.5.4(2021-08-16)
|
||||
- fix: 字节小程序兼容
|
||||
## 1.8.5.3(2021-08-15)
|
||||
- fix: 修复线性渐变与css现实效果不一致的问题
|
||||
- chore: 更新文档
|
||||
## 1.8.5.2(2021-08-13)
|
||||
- chore: 增加`background-image`、`background-repeat` 能力,主要用于背景纹理的绘制,并不是代替`image`。例如:大面积的重复平铺的水印
|
||||
- 注意:这个功能H5暂时无法使用,因为[官方的API有BUG](https://ask.dcloud.net.cn/question/128793),待官方修复!!!
|
||||
## 1.8.5.1(2021-08-10)
|
||||
- fix: 修复因`margin`报错问题
|
||||
## 1.8.5(2021-08-09)
|
||||
- chore: 增加margin支持`auto`,以达到居中效果
|
||||
## 1.8.4(2021-08-06)
|
||||
- chore: 增加判断缓存文件条件
|
||||
- fix: 修复css 多余空格报错问题
|
||||
## 1.8.3(2021-08-04)
|
||||
- tips: 1.6.x 以下的版本升级到1.8.x后要为每个元素都加上定位:position: 'absolute'
|
||||
- fix: 修复只有一个view子元素时不计算高度的问题
|
||||
## 1.8.2(2021-08-03)
|
||||
- fix: 修复 path-type 为 `url` 无效问题
|
||||
- fix: 修复 qrcode `text` 为空时报错问题
|
||||
- fix: 修复 image `src` 动态设置时不生效问题
|
||||
- feat: 增加 css 属性 `min-width` `max-width`
|
||||
## 1.8.1(2021-08-02)
|
||||
- fix: 修复无法加载本地图片
|
||||
## 1.8.0(2021-08-02)
|
||||
- chore 文档更新
|
||||
- 使用旧版的同学不要升级!
|
||||
## 1.8.0-beta(2021-07-30)
|
||||
- ## 全新布局方式 不兼容旧版!
|
||||
- chore: 布局方式变更
|
||||
- tips: 微信canvas 2d 不支持真机调试
|
||||
## 1.6.6(2021-07-09)
|
||||
- chore: 统一命名规范,无须主动引入组件
|
||||
## 1.6.5(2021-06-08)
|
||||
- chore: 去掉console
|
||||
## 1.6.4(2021-06-07)
|
||||
- fix: 修复 数字 为纯字符串时不转换的BUG
|
||||
## 1.6.3(2021-06-06)
|
||||
- fix: 修复 PC 端放大的BUG
|
||||
## 1.6.2(2021-05-31)
|
||||
- fix: 修复 报`adaptor is not a function`错误
|
||||
- fix: 修复 text 多行高度
|
||||
- fix: 优化 默认文字的基准线
|
||||
- feat: `@progress`事件,监听绘制进度
|
||||
## 1.6.1(2021-02-28)
|
||||
- 删除多余节点
|
||||
## 1.6.0(2021-02-26)
|
||||
- 调整为uni_modules目录规范
|
||||
- 修复:transform的rotate不能为负数问题
|
||||
- 新增:`pathType` 指定生成图片返回的路径类型,可选值有 `base64`、`url`
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
const styles = (v ='') => v.split(';').filter(v => v && !/^[\n\s]+$/.test(v)).map(v => {
|
||||
const key = v.slice(0, v.indexOf(':'))
|
||||
const value = v.slice(v.indexOf(':')+1)
|
||||
return {
|
||||
[key
|
||||
.replace(/-([a-z])/g, function() { return arguments[1].toUpperCase()})
|
||||
.replace(/\s+/g, '')
|
||||
]: value.replace(/^\s+/, '').replace(/\s+$/, '') || ''
|
||||
}
|
||||
})
|
||||
export function parent(parent) {
|
||||
return {
|
||||
provide() {
|
||||
return {
|
||||
[parent]: this
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
el: {
|
||||
id: null,
|
||||
css: {},
|
||||
views: []
|
||||
},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
css: {
|
||||
handler(v) {
|
||||
if(this.canvasId) {
|
||||
this.el.css = (typeof v == 'object' ? v : v && Object.assign(...styles(v))) || {}
|
||||
this.canvasWidth = this.el.css && this.el.css.width || this.canvasWidth
|
||||
this.canvasHeight = this.el.css && this.el.css.height || this.canvasHeight
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
export function children(parent, options = {}) {
|
||||
const indexKey = options.indexKey || 'index'
|
||||
return {
|
||||
inject: {
|
||||
[parent]: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
el: {
|
||||
handler(v, o) {
|
||||
if(JSON.stringify(v) != JSON.stringify(o))
|
||||
this.bindRelation()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
},
|
||||
src: {
|
||||
handler(v, o) {
|
||||
if(v != o)
|
||||
this.bindRelation()
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
text: {
|
||||
handler(v, o) {
|
||||
if(v != o) this.bindRelation()
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
css: {
|
||||
handler(v, o) {
|
||||
if(v != o)
|
||||
this.el.css = (typeof v == 'object' ? v : v && Object.assign(...styles(v))) || {}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
replace: {
|
||||
handler(v, o) {
|
||||
if(JSON.stringify(v) != JSON.stringify(o))
|
||||
this.bindRelation()
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(!this._uid) {
|
||||
this._uid = this._.uid
|
||||
}
|
||||
Object.defineProperty(this, 'parent', {
|
||||
get: () => this[parent] || [],
|
||||
})
|
||||
Object.defineProperty(this, 'index', {
|
||||
get: () => {
|
||||
this.bindRelation();
|
||||
const {parent: {el: {views=[]}={}}={}} = this
|
||||
return views.indexOf(this.el)
|
||||
},
|
||||
});
|
||||
this.el.type = this.type
|
||||
if(this.uid) {
|
||||
this.el.uid = this.uid
|
||||
}
|
||||
this.bindRelation()
|
||||
},
|
||||
// #ifdef VUE3
|
||||
beforeUnmount() {
|
||||
this.removeEl()
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE2
|
||||
beforeDestroy() {
|
||||
this.removeEl()
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
removeEl() {
|
||||
if (this.parent) {
|
||||
this.parent.el.views = this.parent.el.views.filter(
|
||||
(item) => item._uid !== this._uid
|
||||
);
|
||||
}
|
||||
},
|
||||
bindRelation() {
|
||||
if(!this.el._uid) {
|
||||
this.el._uid = this._uid
|
||||
}
|
||||
if(['text','qrcode'].includes(this.type)) {
|
||||
this.el.text = this.$slots && this.$slots.default && this.$slots.default[0].text || `${this.text || ''}`.replace(/\\n/g, '\n')
|
||||
}
|
||||
if(this.type == 'image') {
|
||||
this.el.src = this.src
|
||||
}
|
||||
if (!this.parent) {
|
||||
return;
|
||||
}
|
||||
let views = this.parent.el.views || [];
|
||||
if(views.indexOf(this.el) !== -1) {
|
||||
this.parent.el.views = views.map(v => v._uid == this._uid ? this.el : v)
|
||||
} else {
|
||||
this.parent.el.views = [...views, this.el];
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.bindRelation()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {parent, children} from '../common/relation';
|
||||
export default {
|
||||
name: 'lime-painter-image',
|
||||
mixins:[children('painter')],
|
||||
props: {
|
||||
id: String,
|
||||
css: [String, Object],
|
||||
src: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'image',
|
||||
el: {
|
||||
css: {},
|
||||
src: null
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {parent, children} from '../common/relation';
|
||||
export default {
|
||||
name: 'lime-painter-qrcode',
|
||||
mixins:[children('painter')],
|
||||
props: {
|
||||
id: String,
|
||||
css: [String, Object],
|
||||
text: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'qrcode',
|
||||
el: {
|
||||
css: {},
|
||||
text: null
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<text style="opacity: 0;height: 0;"><slot/></text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {parent, children} from '../common/relation';
|
||||
export default {
|
||||
name: 'lime-painter-text',
|
||||
mixins:[children('painter')],
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
uid: String,
|
||||
css: [String, Object],
|
||||
text: [String, Number],
|
||||
replace: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// type: 'text',
|
||||
el: {
|
||||
css: {},
|
||||
text: null
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<view><slot/></view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {parent, children} from '../common/relation';
|
||||
export default {
|
||||
name: 'lime-painter-view',
|
||||
mixins:[children('painter'), parent('painter')],
|
||||
props: {
|
||||
id: String,
|
||||
type: {
|
||||
type: String,
|
||||
default: 'view'
|
||||
},
|
||||
css: [String, Object],
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// type: 'view',
|
||||
el: {
|
||||
css: {},
|
||||
views:[]
|
||||
},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
@ -0,0 +1,461 @@
|
|||
<template>
|
||||
<view class="lime-painter" ref="limepainter">
|
||||
<view v-if="canvasId && size" :style="styles">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<canvas class="lime-painter__canvas" v-if="use2dCanvas" :id="canvasId" type="2d" :style="size"></canvas>
|
||||
<canvas class="lime-painter__canvas" v-else :id="canvasId" :canvas-id="canvasId" :style="size"
|
||||
:width="boardWidth * dpr" :height="boardHeight * dpr" :hidpi="hidpi"></canvas>
|
||||
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<web-view :style="size" ref="webview"
|
||||
src="/uni_modules/lime-painter/hybrid/html/index.html"
|
||||
class="lime-painter__canvas" @pagefinish="onPageFinish" @error="onError" @onPostMessage="onMessage">
|
||||
</web-view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { parent } from '../common/relation'
|
||||
import props from './props'
|
||||
import {toPx, base64ToPath, pathToBase64, isBase64, sleep, getImageInfo }from './utils';
|
||||
// #ifndef APP-NVUE
|
||||
import { canIUseCanvas2d, isPC} from './utils';
|
||||
import Painter from './painter';
|
||||
// import Painter from '@painter'
|
||||
const nvue = {}
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
import nvue from './nvue'
|
||||
// #endif
|
||||
export default {
|
||||
name: 'lime-painter',
|
||||
mixins: [props, parent('painter'), nvue],
|
||||
data() {
|
||||
return {
|
||||
use2dCanvas: false,
|
||||
canvasHeight: 150,
|
||||
canvasWidth: null,
|
||||
parentWidth: 0,
|
||||
inited: false,
|
||||
progress: 0,
|
||||
firstRender: 0,
|
||||
done: false,
|
||||
tasks: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
styles() {
|
||||
return `${this.size}${this.customStyle||''};` + (this.hidden && 'position: fixed; left: 1500rpx;')
|
||||
},
|
||||
canvasId() {
|
||||
return `l-painter${this._ && this._.uid || this._uid}`
|
||||
},
|
||||
size() {
|
||||
if (this.boardWidth && this.boardHeight) {
|
||||
return `width:${this.boardWidth}px; height: ${this.boardHeight}px;`;
|
||||
}
|
||||
},
|
||||
dpr() {
|
||||
return this.pixelRatio || uni.getSystemInfoSync().pixelRatio;
|
||||
},
|
||||
boardWidth() {
|
||||
const {width = 0} = (this.elements && this.elements.css) || this.elements || this
|
||||
const w = toPx(width||this.width)
|
||||
return w || Math.max(w, toPx(this.canvasWidth));
|
||||
},
|
||||
boardHeight() {
|
||||
const {height = 0} = (this.elements && this.elements.css) || this.elements || this
|
||||
const h = toPx(height||this.height)
|
||||
return h || Math.max(h, toPx(this.canvasHeight));
|
||||
},
|
||||
hasBoard() {
|
||||
return this.board && Object.keys(this.board).length
|
||||
},
|
||||
elements() {
|
||||
return this.hasBoard ? this.board : JSON.parse(JSON.stringify(this.el))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.use2dCanvas = this.type === '2d' && canIUseCanvas2d() && !isPC
|
||||
},
|
||||
async mounted() {
|
||||
await sleep(30)
|
||||
await this.getParentWeith()
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.$watch('elements', this.watchRender, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
});
|
||||
}, 30)
|
||||
})
|
||||
},
|
||||
// #ifdef VUE3
|
||||
unmounted() {
|
||||
this.done = false
|
||||
this.inited = false
|
||||
this.firstRender = 0
|
||||
this.progress = 0
|
||||
this.painter = null
|
||||
clearTimeout(this.rendertimer)
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE2
|
||||
destroyed() {
|
||||
this.done = false
|
||||
this.inited = false
|
||||
this.firstRender = 0
|
||||
this.progress = 0
|
||||
this.painter = null
|
||||
clearTimeout(this.rendertimer)
|
||||
},
|
||||
// #endif
|
||||
methods: {
|
||||
async watchRender(val, old) {
|
||||
if (!val || !val.views || (!this.firstRender ? !val.views.length : !this.firstRender) || !Object.keys(val).length || JSON.stringify(val) == JSON.stringify(old)) return;
|
||||
this.firstRender = 1
|
||||
this.progress = 0
|
||||
this.done = false
|
||||
clearTimeout(this.rendertimer)
|
||||
this.rendertimer = setTimeout(() => {
|
||||
this.render(val);
|
||||
}, this.beforeDelay)
|
||||
},
|
||||
async setFilePath(path, param) {
|
||||
let filePath = path
|
||||
const {pathType = this.pathType} = param || this
|
||||
if (pathType == 'base64' && !isBase64(path)) {
|
||||
filePath = await pathToBase64(path)
|
||||
} else if (pathType == 'url' && isBase64(path)) {
|
||||
filePath = await base64ToPath(path)
|
||||
}
|
||||
if (param && param.isEmit) {
|
||||
this.$emit('success', filePath);
|
||||
}
|
||||
return filePath
|
||||
},
|
||||
async getSize(args) {
|
||||
const {width} = args.css || args
|
||||
const {height} = args.css || args
|
||||
if (!this.size) {
|
||||
if (width || height) {
|
||||
this.canvasWidth = width || this.canvasWidth
|
||||
this.canvasHeight = height || this.canvasHeight
|
||||
await sleep(30);
|
||||
} else {
|
||||
await this.getParentWeith()
|
||||
}
|
||||
}
|
||||
},
|
||||
canvasToTempFilePathSync(args) {
|
||||
// this.stopWatch && this.stopWatch()
|
||||
// this.stopWatch = this.$watch('done', (v) => {
|
||||
// if (v) {
|
||||
// this.canvasToTempFilePath(args)
|
||||
// this.stopWatch && this.stopWatch()
|
||||
// }
|
||||
// }, {
|
||||
// immediate: true
|
||||
// })
|
||||
this.tasks.push(args)
|
||||
if(this.done){
|
||||
this.runTask()
|
||||
}
|
||||
},
|
||||
runTask(){
|
||||
while(this.tasks.length){
|
||||
const task = this.tasks.shift()
|
||||
this.canvasToTempFilePath(task)
|
||||
}
|
||||
},
|
||||
// #ifndef APP-NVUE
|
||||
getParentWeith() {
|
||||
return new Promise(resolve => {
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`.lime-painter`)
|
||||
.boundingClientRect()
|
||||
.exec(res => {
|
||||
const {width, height} = res[0]||{}
|
||||
this.parentWidth = Math.ceil(width||0)
|
||||
this.canvasWidth = this.parentWidth || 300
|
||||
this.canvasHeight = height || this.canvasHeight||150
|
||||
resolve(res[0])
|
||||
})
|
||||
})
|
||||
},
|
||||
async render(args = {}) {
|
||||
if(!Object.keys(args).length) {
|
||||
return console.error('空对象')
|
||||
}
|
||||
this.progress = 0
|
||||
this.done = false
|
||||
// #ifdef APP-NVUE
|
||||
this.tempFilePath.length = 0
|
||||
// #endif
|
||||
await this.getSize(args)
|
||||
const ctx = await this.getContext();
|
||||
|
||||
let {
|
||||
use2dCanvas,
|
||||
boardWidth,
|
||||
boardHeight,
|
||||
canvas,
|
||||
afterDelay
|
||||
} = this;
|
||||
if (use2dCanvas && !canvas) {
|
||||
return Promise.reject(new Error('canvas 没创建'));
|
||||
}
|
||||
this.boundary = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: boardWidth,
|
||||
height: boardHeight
|
||||
};
|
||||
this.painter = null
|
||||
if (!this.painter) {
|
||||
const {width} = args.css || args
|
||||
const {height} = args.css || args
|
||||
if(!width && this.parentWidth) {
|
||||
Object.assign(args, {width: this.parentWidth})
|
||||
}
|
||||
const param = {
|
||||
context: ctx,
|
||||
canvas,
|
||||
width: boardWidth,
|
||||
height: boardHeight,
|
||||
pixelRatio: this.dpr,
|
||||
useCORS: this.useCORS,
|
||||
createImage: getImageInfo.bind(this),
|
||||
performance: this.performance,
|
||||
listen: {
|
||||
onProgress: (v) => {
|
||||
this.progress = v
|
||||
this.$emit('progress', v)
|
||||
},
|
||||
onEffectFail: (err) => {
|
||||
this.$emit('faill', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.painter = new Painter(param)
|
||||
}
|
||||
try{
|
||||
// vue3 赋值给data会引起图片无法绘制
|
||||
const { width, height } = await this.painter.source(JSON.parse(JSON.stringify(args)))
|
||||
this.boundary.height = this.canvasHeight = height
|
||||
this.boundary.width = this.canvasWidth = width
|
||||
await sleep(this.sleep);
|
||||
await this.painter.render()
|
||||
await new Promise(resolve => this.$nextTick(resolve));
|
||||
if (!use2dCanvas) {
|
||||
await this.canvasDraw();
|
||||
}
|
||||
if (afterDelay && use2dCanvas) {
|
||||
await sleep(afterDelay);
|
||||
}
|
||||
this.$emit('done');
|
||||
this.done = true
|
||||
if (this.isCanvasToTempFilePath) {
|
||||
this.canvasToTempFilePath()
|
||||
.then(res => {
|
||||
this.$emit('success', res.tempFilePath)
|
||||
})
|
||||
.catch(err => {
|
||||
this.$emit('fail', new Error(JSON.stringify(err)));
|
||||
});
|
||||
}
|
||||
this.runTask()
|
||||
return Promise.resolve({
|
||||
ctx,
|
||||
draw: this.painter,
|
||||
node: this.node
|
||||
});
|
||||
}catch(e){
|
||||
//TODO handle the exception
|
||||
}
|
||||
|
||||
},
|
||||
canvasDraw(flag = false) {
|
||||
return new Promise((resolve, reject) => this.ctx.draw(flag, () => setTimeout(() => resolve(), this
|
||||
.afterDelay)));
|
||||
},
|
||||
async getContext() {
|
||||
if (!this.canvasWidth) {
|
||||
this.$emit('fail', 'painter no size')
|
||||
console.error('[lime-painter]: 给画板或父级设置尺寸')
|
||||
return Promise.reject();
|
||||
}
|
||||
if (this.ctx && this.inited) {
|
||||
return Promise.resolve(this.ctx);
|
||||
}
|
||||
const { type, use2dCanvas, dpr, boardWidth, boardHeight } = this;
|
||||
const _getContext = () => {
|
||||
return new Promise(resolve => {
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`#${this.canvasId}`)
|
||||
.boundingClientRect()
|
||||
.exec(res => {
|
||||
if (res) {
|
||||
const ctx = uni.createCanvasContext(this.canvasId, this);
|
||||
if (!this.inited) {
|
||||
this.inited = true;
|
||||
this.use2dCanvas = false;
|
||||
this.canvas = res;
|
||||
}
|
||||
|
||||
// 钉钉小程序框架不支持 measureText 方法,用此方法 mock
|
||||
if (!ctx.measureText) {
|
||||
function strLen(str) {
|
||||
let len = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
|
||||
len++;
|
||||
} else {
|
||||
len += 2;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
ctx.measureText = text => {
|
||||
let fontSize = ctx.state && ctx.state.fontSize || 12;
|
||||
const font = ctx.__font
|
||||
if (font && fontSize == 12) {
|
||||
fontSize = parseInt(font.split(' ')[3], 10);
|
||||
}
|
||||
fontSize /= 2;
|
||||
return {
|
||||
width: strLen(text) * fontSize
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
ctx.scale(dpr, dpr);
|
||||
// #endif
|
||||
this.ctx = ctx
|
||||
resolve(this.ctx);
|
||||
} else {
|
||||
console.error('[lime-painter] no node')
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
if (!use2dCanvas) {
|
||||
return _getContext();
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
uni.createSelectorQuery()
|
||||
.in(this)
|
||||
.select(`#${this.canvasId}`)
|
||||
.node()
|
||||
.exec(res => {
|
||||
let {node: canvas} = res && res[0]||{};
|
||||
if(canvas) {
|
||||
const ctx = canvas.getContext(type);
|
||||
if (!this.inited) {
|
||||
this.inited = true;
|
||||
this.use2dCanvas = true;
|
||||
this.canvas = canvas;
|
||||
}
|
||||
this.ctx = ctx
|
||||
resolve(this.ctx);
|
||||
} else {
|
||||
console.error('[lime-painter]: no size')
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
canvasToTempFilePath(args = {}) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { use2dCanvas, canvasId, dpr, fileType, quality } = this;
|
||||
const success = async (res) => {
|
||||
try {
|
||||
const tempFilePath = await this.setFilePath(res.tempFilePath || res, args)
|
||||
const result = Object.assign(res, {tempFilePath})
|
||||
args.success && args.success(result)
|
||||
resolve(result)
|
||||
} catch (e) {
|
||||
this.$emit('fail', e)
|
||||
}
|
||||
}
|
||||
|
||||
let { top: y = 0, left: x = 0, width, height } = this.boundary || this;
|
||||
// let destWidth = width * dpr;
|
||||
// let destHeight = height * dpr;
|
||||
// #ifdef MP-ALIPAY
|
||||
// width = destWidth;
|
||||
// height = destHeight;
|
||||
// #endif
|
||||
|
||||
const copyArgs = Object.assign({
|
||||
// x,
|
||||
// y,
|
||||
// width,
|
||||
// height,
|
||||
// destWidth,
|
||||
// destHeight,
|
||||
canvasId,
|
||||
id: canvasId,
|
||||
fileType,
|
||||
quality,
|
||||
}, args, {success});
|
||||
// if(this.isPC || use2dCanvas) {
|
||||
// copyArgs.canvas = this.canvas
|
||||
// }
|
||||
if (use2dCanvas) {
|
||||
copyArgs.canvas = this.canvas
|
||||
try{
|
||||
// #ifndef MP-ALIPAY
|
||||
const oFilePath = this.canvas.toDataURL(`image/${args.fileType||fileType}`.replace(/pg/, 'peg'), args.quality||quality)
|
||||
if(/data:,/.test(oFilePath)) {
|
||||
uni.canvasToTempFilePath(copyArgs, this);
|
||||
} else {
|
||||
const tempFilePath = await this.setFilePath(oFilePath, args)
|
||||
args.success && args.success({tempFilePath})
|
||||
resolve({tempFilePath})
|
||||
}
|
||||
// #endif
|
||||
// #ifdef MP-ALIPAY
|
||||
this.canvas.toTempFilePath(copyArgs)
|
||||
// #endif
|
||||
}catch(e){
|
||||
args.fail && args.fail(e)
|
||||
reject(e)
|
||||
}
|
||||
} else {
|
||||
// #ifdef MP-ALIPAY
|
||||
if(this.ctx.toTempFilePath) {
|
||||
// 钉钉
|
||||
const ctx = uni.createCanvasContext(canvasId);
|
||||
ctx.toTempFilePath(copyArgs);
|
||||
} else {
|
||||
my.canvasToTempFilePath(copyArgs);
|
||||
}
|
||||
// #endif
|
||||
// #ifndef MP-ALIPAY
|
||||
uni.canvasToTempFilePath(copyArgs, this);
|
||||
// #endif
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.lime-painter,
|
||||
.lime-painter__canvas {
|
||||
// #ifndef APP-NVUE
|
||||
width: 100%;
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
flex: 1;
|
||||
// #endif
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
// #ifdef APP-NVUE
|
||||
import { sleep, getImageInfo, isBase64, useNvue, networkReg } from './utils';
|
||||
const dom = weex.requireModule('dom')
|
||||
import { version } from '../../package.json'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tempFilePath: [],
|
||||
isInitFile: false,
|
||||
osName: uni.getSystemInfoSync().osName
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getParentWeith() {
|
||||
return new Promise(resolve => {
|
||||
dom.getComponentRect(this.$refs.limepainter, (res) => {
|
||||
this.parentWidth = Math.ceil(res.size.width)
|
||||
this.canvasWidth = this.canvasWidth || this.parentWidth ||300
|
||||
this.canvasHeight = res.size.height || this.canvasHeight||150
|
||||
resolve(res.size)
|
||||
})
|
||||
})
|
||||
},
|
||||
onPageFinish() {
|
||||
this.webview = this.$refs.webview
|
||||
this.webview.evalJS(`init(${this.dpr})`)
|
||||
},
|
||||
onMessage(e) {
|
||||
const res = e.detail.data[0] || null;
|
||||
if (res.event) {
|
||||
if (res.event == 'inited') {
|
||||
this.inited = true
|
||||
}
|
||||
if(res.event == 'fail'){
|
||||
this.$emit('fail', res)
|
||||
}
|
||||
if (res.event == 'layoutChange') {
|
||||
const data = typeof res.data == 'string' ? JSON.parse(res.data) : res.data
|
||||
this.canvasWidth = Math.ceil(data.width);
|
||||
this.canvasHeight = Math.ceil(data.height);
|
||||
}
|
||||
if (res.event == 'progressChange') {
|
||||
this.progress = res.data * 1
|
||||
}
|
||||
if (res.event == 'file') {
|
||||
this.tempFilePath.push(res.data)
|
||||
if (this.tempFilePath.length > 7) {
|
||||
this.tempFilePath.shift()
|
||||
}
|
||||
return
|
||||
}
|
||||
if (res.event == 'success') {
|
||||
if (res.data) {
|
||||
this.tempFilePath.push(res.data)
|
||||
if (this.tempFilePath.length > 8) {
|
||||
this.tempFilePath.shift()
|
||||
}
|
||||
if (this.isCanvasToTempFilePath) {
|
||||
this.setFilePath(this.tempFilePath.join(''), {isEmit:true})
|
||||
}
|
||||
} else {
|
||||
this.$emit('fail', 'canvas no data')
|
||||
}
|
||||
return
|
||||
}
|
||||
this.$emit(res.event, JSON.parse(res.data));
|
||||
} else if (res.file) {
|
||||
this.file = res.data;
|
||||
} else{
|
||||
console.info(res[0])
|
||||
}
|
||||
},
|
||||
getWebViewInited() {
|
||||
if (this.inited) return Promise.resolve(this.inited);
|
||||
return new Promise((resolve) => {
|
||||
this.$watch(
|
||||
'inited',
|
||||
async val => {
|
||||
if (val) {
|
||||
resolve(val)
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
})
|
||||
},
|
||||
getTempFilePath() {
|
||||
if (this.tempFilePath.length == 8) return Promise.resolve(this.tempFilePath)
|
||||
return new Promise((resolve) => {
|
||||
this.$watch(
|
||||
'tempFilePath',
|
||||
async val => {
|
||||
if (val.length == 8) {
|
||||
resolve(val.join(''))
|
||||
}
|
||||
}
|
||||
);
|
||||
})
|
||||
},
|
||||
getWebViewDone() {
|
||||
if (this.progress == 1) return Promise.resolve(this.progress);
|
||||
return new Promise((resolve) => {
|
||||
this.$watch(
|
||||
'progress',
|
||||
async val => {
|
||||
if (val == 1) {
|
||||
this.$emit('done')
|
||||
this.done = true
|
||||
this.runTask()
|
||||
resolve(val)
|
||||
}
|
||||
}, {
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
})
|
||||
},
|
||||
async render(args) {
|
||||
try {
|
||||
await this.getSize(args)
|
||||
const {width} = args.css || args
|
||||
if(!width && this.parentWidth) {
|
||||
Object.assign(args, {width: this.parentWidth})
|
||||
}
|
||||
const newNode = await this.calcImage(args);
|
||||
await this.getWebViewInited()
|
||||
this.webview.evalJS(`source(${JSON.stringify(newNode)})`)
|
||||
await this.getWebViewDone()
|
||||
await sleep(this.afterDelay)
|
||||
if (this.isCanvasToTempFilePath) {
|
||||
const params = {
|
||||
fileType: this.fileType,
|
||||
quality: this.quality
|
||||
}
|
||||
this.webview.evalJS(`save(${JSON.stringify(params)})`)
|
||||
}
|
||||
return Promise.resolve()
|
||||
} catch (e) {
|
||||
this.$emit('fail', e)
|
||||
}
|
||||
},
|
||||
async calcImage(args) {
|
||||
let node = JSON.parse(JSON.stringify(args))
|
||||
const urlReg = /url\((.+)\)/
|
||||
const {backgroundImage} = node.css||{}
|
||||
const isBG = backgroundImage && urlReg.exec(backgroundImage)[1]
|
||||
const url = node.url || node.src || isBG
|
||||
if(['text', 'qrcode'].includes(node.type)) {
|
||||
return node
|
||||
}
|
||||
if ((node.type === "image" || isBG) && url && !isBase64(url) && (this.osName == 'ios' || !networkReg.test(url))) {
|
||||
let {path} = await getImageInfo(url, true)
|
||||
if (isBG) {
|
||||
node.css.backgroundImage = `url(${path})`
|
||||
} else {
|
||||
node.src = path
|
||||
}
|
||||
} else if (node.views && node.views.length) {
|
||||
for (let i = 0; i < node.views.length; i++) {
|
||||
node.views[i] = await this.calcImage(node.views[i])
|
||||
}
|
||||
}
|
||||
return node
|
||||
},
|
||||
async canvasToTempFilePath(args = {}) {
|
||||
if (!this.inited) {
|
||||
return this.$emit('fail', 'no init')
|
||||
}
|
||||
this.tempFilePath = []
|
||||
if (args.fileType == 'jpg') {
|
||||
args.fileType = 'jpeg'
|
||||
}
|
||||
this.webview.evalJS(`save(${JSON.stringify(args)})`)
|
||||
try {
|
||||
let tempFilePath = await this.getTempFilePath()
|
||||
tempFilePath = await this.setFilePath(tempFilePath, args)
|
||||
args.success({
|
||||
errMsg: "canvasToTempFilePath:ok",
|
||||
tempFilePath
|
||||
})
|
||||
} catch (e) {
|
||||
args.fail({
|
||||
error: e
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
export default {
|
||||
props: {
|
||||
board: Object,
|
||||
pathType: String, // 'base64'、'url'
|
||||
fileType: {
|
||||
type: String,
|
||||
default: 'png'
|
||||
},
|
||||
hidden: Boolean,
|
||||
quality: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
css: [String, Object],
|
||||
// styles: [String, Object],
|
||||
width: [Number, String],
|
||||
height: [Number, String],
|
||||
pixelRatio: Number,
|
||||
customStyle: String,
|
||||
isCanvasToTempFilePath: Boolean,
|
||||
// useCanvasToTempFilePath: Boolean,
|
||||
sleep: {
|
||||
type: Number,
|
||||
default: 1000 / 30
|
||||
},
|
||||
beforeDelay: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
afterDelay: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
performance: Boolean,
|
||||
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||
type: {
|
||||
type: String,
|
||||
default: '2d'
|
||||
},
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
hybrid: Boolean,
|
||||
timeout: {
|
||||
type: Number,
|
||||
default: 2000
|
||||
},
|
||||
// #endif
|
||||
// #ifdef H5 || APP-PLUS
|
||||
useCORS: Boolean,
|
||||
hidpi: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||