upda
parent
1ccbf64d4a
commit
853daaf00a
@ -0,0 +1,8 @@
|
|||||||
|
.project
|
||||||
|
.hbuilderx
|
||||||
|
.mini-ide
|
||||||
|
.idea
|
||||||
|
unpackage
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
node_modules
|
||||||
@ -1,17 +1,23 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
onLaunch: function() {
|
onLaunch: function () {
|
||||||
console.log('App Launch')
|
console.log('App Launch')
|
||||||
},
|
},
|
||||||
onShow: function() {
|
onShow: function () {
|
||||||
console.log('App Show')
|
console.log('App Show')
|
||||||
},
|
},
|
||||||
onHide: function() {
|
onHide: function () {
|
||||||
console.log('App Hide')
|
console.log('App Hide')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style lang="scss">
|
||||||
/*每个页面公共css */
|
/*每个页面公共css */
|
||||||
|
@import "tailwindcss/base";
|
||||||
|
@import "tailwindcss/utilities";
|
||||||
|
|
||||||
|
page {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
const files = require.context("./modules", false, /\.js$/),
|
||||||
|
api = {};
|
||||||
|
|
||||||
|
files.keys().forEach((key) => {
|
||||||
|
const last = key.indexOf(".js"),
|
||||||
|
name = key.slice(2, last);
|
||||||
|
|
||||||
|
api[name] = files(key).default;
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...api,
|
||||||
|
};
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import {
|
||||||
|
request
|
||||||
|
} from "@/utils/request";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// 登录
|
||||||
|
login(data) {
|
||||||
|
return request({
|
||||||
|
url: "/admin/auth/login",
|
||||||
|
method: "POST",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<view class="myTable">
|
||||||
|
<wd-pagination v-model="value" :total="total" :page-size="page" @change="handleChange" show-icon show-message />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
apiObj: {
|
||||||
|
type: Function,
|
||||||
|
default: () => (() => { })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const value = ref("")
|
||||||
|
const total = ref(0)
|
||||||
|
const page = ref(1)
|
||||||
|
|
||||||
|
function handleChange(e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss"></style>
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
export default {
|
||||||
|
host: "https://saasdemo.byin.vip",
|
||||||
|
NETWORK_TIME_OUT: 15000,
|
||||||
|
};
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"autoprefixer": "^10.4.8",
|
||||||
|
"postcss": "^8.4.14",
|
||||||
|
"postcss-rem-to-responsive-pixel": "^5.1.3",
|
||||||
|
"tailwindcss": "^3.1.7",
|
||||||
|
"weapp-tailwindcss-webpack-plugin": "^1.6.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"js-md5": "^0.8.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,52 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="content">
|
<view class="content">
|
||||||
<image class="logo" src="/static/logo.png"></image>
|
<wd-button>主要按钮</wd-button>
|
||||||
<view class="text-area">
|
<wd-button type="success">成功按钮</wd-button>
|
||||||
<text class="title">{{title}}</text>
|
<wd-button type="info">信息按钮</wd-button>
|
||||||
</view>
|
<wd-button type="warning">警告按钮</wd-button>
|
||||||
|
<wd-button type="error">危险按钮</wd-button>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
export default {
|
import utils from '@/utils/utils.js'
|
||||||
data() {
|
const user_info = uni.getStorageSync("user_info");
|
||||||
return {
|
if (user_info.type == 1) {
|
||||||
title: 'Hello'
|
utils.toUrl("/store/index/index")
|
||||||
}
|
}
|
||||||
},
|
|
||||||
onLoad() {
|
|
||||||
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
height: 200rpx;
|
height: 200rpx;
|
||||||
width: 200rpx;
|
width: 200rpx;
|
||||||
margin-top: 200rpx;
|
margin-top: 200rpx;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-bottom: 50rpx;
|
margin-bottom: 50rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-area {
|
.text-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: 36rpx;
|
font-size: 36rpx;
|
||||||
color: #8f8f94;
|
color: #8f8f94;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content min-h-dvh flex items-center justify-center">
|
||||||
|
<wd-form class="mb-36" ref="form" :model="model">
|
||||||
|
<wd-cell-group border>
|
||||||
|
<wd-input label="用户名" label-width="100px" prop="username" clearable v-model="model.username" placeholder="请输入用户名"
|
||||||
|
:rules="[{ required: true, message: '请填写用户名' }]" />
|
||||||
|
<wd-input label="密码" label-width="100px" prop="password" show-password clearable v-model="model.password"
|
||||||
|
placeholder="请输入密码" :rules="[{ required: true, message: '请填写密码' }]" />
|
||||||
|
</wd-cell-group>
|
||||||
|
<view class="footer mt-4">
|
||||||
|
<wd-button type="primary" size="medium" @click="handleSubmit" block>登录</wd-button>
|
||||||
|
</view>
|
||||||
|
</wd-form>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import user from '@/api/modules/user.js'
|
||||||
|
import utils from '@/utils/utils.js'
|
||||||
|
import md5 from 'js-md5';
|
||||||
|
|
||||||
|
const model = ref({
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = ref(null)
|
||||||
|
function handleSubmit() {
|
||||||
|
|
||||||
|
form.value
|
||||||
|
.validate()
|
||||||
|
.then(({ valid, errors }) => {
|
||||||
|
if (valid) {
|
||||||
|
|
||||||
|
user.login({
|
||||||
|
...model.value,
|
||||||
|
password: md5(model.value.password)
|
||||||
|
}).then(res => {
|
||||||
|
|
||||||
|
if (res.code == 0) {
|
||||||
|
uni.setStorageSync("token", res.data.access_token);
|
||||||
|
uni.setStorageSync("user_info", res.data.user_info);
|
||||||
|
uni.showToast({
|
||||||
|
icon: "none",
|
||||||
|
title: "登录成功",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.type == 1) {
|
||||||
|
utils.toUrl("/store/index/index")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error, 'error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 200rpx;
|
||||||
|
width: 200rpx;
|
||||||
|
margin-top: 200rpx;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #8f8f94;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content p-4">
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import utils from '@/utils/utils.js'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content p-4">
|
||||||
|
<view class="w-full grid grid-cols-2 gap-4">
|
||||||
|
<view @click="utils.toUrl('/store/order/index')"
|
||||||
|
class="text-white bg-gradient-to-r from-orange-200 to-orange-400 shadow rounded-md p-4">
|
||||||
|
<wd-icon name="circle1" size="24px"></wd-icon>
|
||||||
|
<view class="mt-2 text-end font-bold ">订单中心</view>
|
||||||
|
</view>
|
||||||
|
<view @click="utils.toUrl('/store/goods/index')"
|
||||||
|
class="text-white bg-gradient-to-r from-orange-200 to-orange-400 shadow rounded-md p-4">
|
||||||
|
<wd-icon name="goods" size="24px"></wd-icon>
|
||||||
|
<view class="mt-2 text-end font-bold">商品管理</view>
|
||||||
|
</view>
|
||||||
|
<!-- <view class="bg-dark shadow-md rounded-md p-4">
|
||||||
|
<wd-icon name="goods" size="22px"></wd-icon>
|
||||||
|
<view class="mt-2 text-end font-bold">订单中心</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="bg-dark shadow-md rounded-md p-4">
|
||||||
|
<wd-icon name="goods" size="22px"></wd-icon>
|
||||||
|
<view class="mt-2 text-end font-bold">订单中心</view>
|
||||||
|
</view> -->
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import utils from '@/utils/utils.js'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 200rpx;
|
||||||
|
width: 200rpx;
|
||||||
|
margin-top: 200rpx;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-bottom: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-area {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #8f8f94;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content p-4">
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import utils from '@/utils/utils.js'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const resolve = (p) => {
|
||||||
|
return path.resolve(__dirname, p);
|
||||||
|
};
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./index.html", "./**/*.vue"].map(resolve),
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
corePlugins: {
|
||||||
|
preflight: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
// tsconfig.json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"types": [
|
||||||
|
"wot-design-uni/global.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
const _b64chars = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/']
|
||||||
|
const _mkUriSafe = (src) => src.replace(/[+/]/g, (m0) => (m0 === '+' ? '-' : '_')).replace(/=+$/m, '')
|
||||||
|
const fromUint8Array = (src, rfc4648 = false) => {
|
||||||
|
let b64 = ''
|
||||||
|
for (let i = 0, l = src.length; i < l; i += 3) {
|
||||||
|
const [a0, a1, a2] = [src[i], src[i + 1], src[i + 2]]
|
||||||
|
const ord = (a0 << 16) | (a1 << 8) | a2
|
||||||
|
b64 += _b64chars[ord >>> 18]
|
||||||
|
b64 += _b64chars[(ord >>> 12) & 63]
|
||||||
|
b64 += typeof a1 !== 'undefined' ? _b64chars[(ord >>> 6) & 63] : '='
|
||||||
|
b64 += typeof a2 !== 'undefined' ? _b64chars[ord & 63] : '='
|
||||||
|
}
|
||||||
|
return rfc4648 ? _mkUriSafe(b64) : b64
|
||||||
|
}
|
||||||
|
const _btoa =
|
||||||
|
typeof btoa === 'function'
|
||||||
|
? (s) => btoa(s)
|
||||||
|
: (s) => {
|
||||||
|
if (s.charCodeAt() > 255) {
|
||||||
|
throw new RangeError('The string contains invalid characters.')
|
||||||
|
}
|
||||||
|
return fromUint8Array(Uint8Array.from(s, (c: any) => c.charCodeAt(0)))
|
||||||
|
}
|
||||||
|
const utob = (src) => unescape(encodeURIComponent(src))
|
||||||
|
|
||||||
|
export default function encode(src, rfc4648 = false) {
|
||||||
|
const b64 = _btoa(utob(src))
|
||||||
|
return rfc4648 ? _mkUriSafe(b64) : b64
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-07-02 22:51:06
|
||||||
|
* @LastEditTime: 2023-07-13 10:07:17
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\common\clickoutside.ts
|
||||||
|
* 记得注释
|
||||||
|
*/
|
||||||
|
let queue: any[] = []
|
||||||
|
|
||||||
|
export function pushToQueue(comp) {
|
||||||
|
queue.push(comp)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeFromQueue(comp) {
|
||||||
|
queue = queue.filter((item) => {
|
||||||
|
return item.$.uid !== comp.$.uid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeOther(comp) {
|
||||||
|
queue.forEach((item) => {
|
||||||
|
if (item.$.uid !== comp.$.uid) {
|
||||||
|
item.$.exposed.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeOutside() {
|
||||||
|
queue.forEach((item) => {
|
||||||
|
item.$.exposed.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,146 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
class Dayjs {
|
||||||
|
utc: boolean
|
||||||
|
date: Date
|
||||||
|
timeZone: number
|
||||||
|
timeZoneString: any
|
||||||
|
mYear: any
|
||||||
|
mMonth: any
|
||||||
|
mDay: any
|
||||||
|
mWeek: any
|
||||||
|
mHour: any
|
||||||
|
mMinute: any
|
||||||
|
mSecond: any
|
||||||
|
constructor(dateStr) {
|
||||||
|
this.utc = false
|
||||||
|
const parsedDate = this.parseConfig(dateStr)
|
||||||
|
this.date = new Date(parsedDate)
|
||||||
|
this.timeZone = this.date.getTimezoneOffset() / 60
|
||||||
|
this.timeZoneString = this.padNumber(String(-1 * this.timeZone).replace(/^(.)?(\d)/, '$10$200'), 5, '+')
|
||||||
|
this.mYear = this.date.getFullYear()
|
||||||
|
this.mMonth = this.date.getMonth()
|
||||||
|
this.mDay = this.date.getDate()
|
||||||
|
this.mWeek = this.date.getDay()
|
||||||
|
this.mHour = this.date.getHours()
|
||||||
|
this.mMinute = this.date.getMinutes()
|
||||||
|
this.mSecond = this.date.getSeconds()
|
||||||
|
}
|
||||||
|
|
||||||
|
parseConfig(dateStr) {
|
||||||
|
if (!dateStr) return new Date()
|
||||||
|
if (dateStr instanceof Date) return dateStr
|
||||||
|
if (/^(\d){8}$/.test(dateStr)) {
|
||||||
|
this.utc = true
|
||||||
|
return `${dateStr.substr(0, 4)}-${dateStr.substr(4, 2)}-${dateStr.substr(6, 2)}`
|
||||||
|
}
|
||||||
|
return dateStr
|
||||||
|
}
|
||||||
|
|
||||||
|
padNumber(num, length, padChar) {
|
||||||
|
return !num || num.length >= length ? num : `${Array(length + 1 - num.length).join(padChar)}${num}`
|
||||||
|
}
|
||||||
|
|
||||||
|
year() {
|
||||||
|
return this.mYear
|
||||||
|
}
|
||||||
|
|
||||||
|
month() {
|
||||||
|
return this.mMonth
|
||||||
|
}
|
||||||
|
|
||||||
|
unix() {
|
||||||
|
const timeZoneOffset = this.utc ? 60 * this.timeZone * 60 * 1000 : 0
|
||||||
|
return Math.floor((this.date.getTime() + timeZoneOffset) / 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.date.toUTCString()
|
||||||
|
}
|
||||||
|
|
||||||
|
startOf(unit) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
return new Dayjs(new Date(this.year(), 0, 1))
|
||||||
|
case 'month':
|
||||||
|
return new Dayjs(new Date(this.year(), this.month(), 1))
|
||||||
|
default:
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(amount, unit) {
|
||||||
|
let interval
|
||||||
|
switch (unit) {
|
||||||
|
case 'm':
|
||||||
|
case 'minutes':
|
||||||
|
interval = 60
|
||||||
|
break
|
||||||
|
case 'h':
|
||||||
|
case 'hours':
|
||||||
|
interval = 60 * 60
|
||||||
|
break
|
||||||
|
case 'd':
|
||||||
|
case 'days':
|
||||||
|
interval = 24 * 60 * 60
|
||||||
|
break
|
||||||
|
case 'w':
|
||||||
|
case 'weeks':
|
||||||
|
interval = 7 * 24 * 60 * 60
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
interval = 1
|
||||||
|
}
|
||||||
|
const newUnixTime = this.unix() + amount * interval
|
||||||
|
return new Dayjs(1000 * newUnixTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
subtract(amount, unit) {
|
||||||
|
return this.add(-1 * amount, unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
format(formatStr = 'YYYY-MM-DDTHH:mm:ssZ') {
|
||||||
|
const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
|
||||||
|
return formatStr.replace(/Y{2,4}|M{1,2}|D{1,2}|d{1,4}|H{1,2}|m{1,2}|s{1,2}|Z{1,2}/g, (match) => {
|
||||||
|
switch (match) {
|
||||||
|
case 'YY':
|
||||||
|
return String(this.mYear).slice(-2)
|
||||||
|
case 'YYYY':
|
||||||
|
return String(this.mYear)
|
||||||
|
case 'M':
|
||||||
|
return String(this.mMonth + 1)
|
||||||
|
case 'MM':
|
||||||
|
return this.padNumber(String(this.mMonth + 1), 2, '0')
|
||||||
|
case 'D':
|
||||||
|
return String(this.mDay)
|
||||||
|
case 'DD':
|
||||||
|
return this.padNumber(String(this.mDay), 2, '0')
|
||||||
|
case 'd':
|
||||||
|
return String(this.mWeek)
|
||||||
|
case 'dddd':
|
||||||
|
return weekdays[this.mWeek]
|
||||||
|
case 'H':
|
||||||
|
return String(this.mHour)
|
||||||
|
case 'HH':
|
||||||
|
return this.padNumber(String(this.mHour), 2, '0')
|
||||||
|
case 'm':
|
||||||
|
return String(this.mMinute)
|
||||||
|
case 'mm':
|
||||||
|
return this.padNumber(String(this.mMinute), 2, '0')
|
||||||
|
case 's':
|
||||||
|
return String(this.mSecond)
|
||||||
|
case 'ss':
|
||||||
|
return this.padNumber(String(this.mSecond), 2, '0')
|
||||||
|
case 'Z':
|
||||||
|
return `${this.timeZoneString.slice(0, -2)}:00`
|
||||||
|
case 'ZZ':
|
||||||
|
return this.timeZoneString
|
||||||
|
default:
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dayjs(dateStr?: string | number | Date) {
|
||||||
|
return new Dayjs(dateStr)
|
||||||
|
}
|
||||||
@ -0,0 +1,206 @@
|
|||||||
|
import isObject from './isObject'
|
||||||
|
import root from './internal/root'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a debounced function that delays invoking `func` until after `wait`
|
||||||
|
* milliseconds have elapsed since the last time the debounced function was
|
||||||
|
* invoked, or until the next browser frame is drawn. The debounced function
|
||||||
|
* comes with a `cancel` method to cancel delayed `func` invocations and a
|
||||||
|
* `flush` method to immediately invoke them. Provide `options` to indicate
|
||||||
|
* whether `func` should be invoked on the leading and/or trailing edge of the
|
||||||
|
* `wait` timeout. The `func` is invoked with the last arguments provided to the
|
||||||
|
* debounced function. Subsequent calls to the debounced function return the
|
||||||
|
* result of the last `func` invocation.
|
||||||
|
*
|
||||||
|
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
||||||
|
* invoked on the trailing edge of the timeout only if the debounced function
|
||||||
|
* is invoked more than once during the `wait` timeout.
|
||||||
|
*
|
||||||
|
* If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
|
||||||
|
* until the next tick, similar to `setTimeout` with a timeout of `0`.
|
||||||
|
*
|
||||||
|
* If `wait` is omitted in an environment with `requestAnimationFrame`, `func`
|
||||||
|
* invocation will be deferred until the next frame is drawn (typically about
|
||||||
|
* 16ms).
|
||||||
|
*
|
||||||
|
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||||||
|
* for details over the differences between `debounce` and `throttle`.
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
* @category Function
|
||||||
|
* @param {Function} func The function to debounce.
|
||||||
|
* @param {number} [wait=0]
|
||||||
|
* The number of milliseconds to delay; if omitted, `requestAnimationFrame` is
|
||||||
|
* used (if available).
|
||||||
|
* @param {Object} [options={}] The options object.
|
||||||
|
* @param {boolean} [options.leading=false]
|
||||||
|
* Specify invoking on the leading edge of the timeout.
|
||||||
|
* @param {number} [options.maxWait]
|
||||||
|
* The maximum time `func` is allowed to be delayed before it's invoked.
|
||||||
|
* @param {boolean} [options.trailing=true]
|
||||||
|
* Specify invoking on the trailing edge of the timeout.
|
||||||
|
* @returns {Function} Returns the new debounced function.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* // Avoid costly calculations while the window size is in flux.
|
||||||
|
* jQuery(window).on('resize', debounce(calculateLayout, 150))
|
||||||
|
*
|
||||||
|
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
||||||
|
* jQuery(element).on('click', debounce(sendMail, 300, {
|
||||||
|
* 'leading': true,
|
||||||
|
* 'trailing': false
|
||||||
|
* }))
|
||||||
|
*
|
||||||
|
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
||||||
|
* const debounced = debounce(batchLog, 250, { 'maxWait': 1000 })
|
||||||
|
* const source = new EventSource('/stream')
|
||||||
|
* jQuery(source).on('message', debounced)
|
||||||
|
*
|
||||||
|
* // Cancel the trailing debounced invocation.
|
||||||
|
* jQuery(window).on('popstate', debounced.cancel)
|
||||||
|
*
|
||||||
|
* // Check for pending invocations.
|
||||||
|
* const status = debounced.pending() ? "Pending..." : "Ready"
|
||||||
|
*/
|
||||||
|
function debounce(func, wait, options?) {
|
||||||
|
let lastArgs, lastThis, maxWait, result, timerId, lastCallTime
|
||||||
|
|
||||||
|
let lastInvokeTime = 0
|
||||||
|
let leading = false
|
||||||
|
let maxing = false
|
||||||
|
let trailing = true
|
||||||
|
|
||||||
|
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
|
||||||
|
const useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === 'function'
|
||||||
|
|
||||||
|
if (typeof func !== 'function') {
|
||||||
|
throw new TypeError('Expected a function')
|
||||||
|
}
|
||||||
|
wait = +wait || 0
|
||||||
|
if (isObject(options)) {
|
||||||
|
leading = !!options.leading
|
||||||
|
maxing = 'maxWait' in options
|
||||||
|
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait
|
||||||
|
trailing = 'trailing' in options ? !!options.trailing : trailing
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokeFunc(time) {
|
||||||
|
const args = lastArgs
|
||||||
|
const thisArg = lastThis
|
||||||
|
|
||||||
|
lastArgs = lastThis = undefined
|
||||||
|
lastInvokeTime = time
|
||||||
|
result = func.apply(thisArg, args)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTimer(pendingFunc, wait) {
|
||||||
|
if (useRAF) {
|
||||||
|
root.cancelAnimationFrame(timerId)
|
||||||
|
return root.requestAnimationFrame(pendingFunc)
|
||||||
|
}
|
||||||
|
return setTimeout(pendingFunc, wait)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelTimer(id) {
|
||||||
|
if (useRAF) {
|
||||||
|
return root.cancelAnimationFrame(id)
|
||||||
|
}
|
||||||
|
clearTimeout(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
function leadingEdge(time) {
|
||||||
|
// Reset any `maxWait` timer.
|
||||||
|
lastInvokeTime = time
|
||||||
|
// Start the timer for the trailing edge.
|
||||||
|
timerId = startTimer(timerExpired, wait)
|
||||||
|
// Invoke the leading edge.
|
||||||
|
return leading ? invokeFunc(time) : result
|
||||||
|
}
|
||||||
|
|
||||||
|
function remainingWait(time) {
|
||||||
|
const timeSinceLastCall = time - lastCallTime
|
||||||
|
const timeSinceLastInvoke = time - lastInvokeTime
|
||||||
|
const timeWaiting = wait - timeSinceLastCall
|
||||||
|
|
||||||
|
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldInvoke(time) {
|
||||||
|
const timeSinceLastCall = time - lastCallTime
|
||||||
|
const timeSinceLastInvoke = time - lastInvokeTime
|
||||||
|
|
||||||
|
// Either this is the first call, activity has stopped and we're at the
|
||||||
|
// trailing edge, the system time has gone backwards and we're treating
|
||||||
|
// it as the trailing edge, or we've hit the `maxWait` limit.
|
||||||
|
return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || (maxing && timeSinceLastInvoke >= maxWait)
|
||||||
|
}
|
||||||
|
|
||||||
|
function timerExpired() {
|
||||||
|
const time = Date.now()
|
||||||
|
if (shouldInvoke(time)) {
|
||||||
|
return trailingEdge(time)
|
||||||
|
}
|
||||||
|
// Restart the timer.
|
||||||
|
timerId = startTimer(timerExpired, remainingWait(time))
|
||||||
|
}
|
||||||
|
|
||||||
|
function trailingEdge(time) {
|
||||||
|
timerId = undefined
|
||||||
|
|
||||||
|
// Only invoke if we have `lastArgs` which means `func` has been
|
||||||
|
// debounced at least once.
|
||||||
|
if (trailing && lastArgs) {
|
||||||
|
return invokeFunc(time)
|
||||||
|
}
|
||||||
|
lastArgs = lastThis = undefined
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
if (timerId !== undefined) {
|
||||||
|
cancelTimer(timerId)
|
||||||
|
}
|
||||||
|
lastInvokeTime = 0
|
||||||
|
lastArgs = lastCallTime = lastThis = timerId = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function flush() {
|
||||||
|
return timerId === undefined ? result : trailingEdge(Date.now())
|
||||||
|
}
|
||||||
|
|
||||||
|
function pending() {
|
||||||
|
return timerId !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
function debounced(this: any, ...args) {
|
||||||
|
const time = Date.now()
|
||||||
|
const isInvoking = shouldInvoke(time)
|
||||||
|
|
||||||
|
lastArgs = args
|
||||||
|
lastThis = this
|
||||||
|
lastCallTime = time
|
||||||
|
|
||||||
|
if (isInvoking) {
|
||||||
|
if (timerId === undefined) {
|
||||||
|
return leadingEdge(lastCallTime)
|
||||||
|
}
|
||||||
|
if (maxing) {
|
||||||
|
// Handle invocations in a tight loop.
|
||||||
|
timerId = startTimer(timerExpired, wait)
|
||||||
|
return invokeFunc(lastCallTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (timerId === undefined) {
|
||||||
|
timerId = startTimer(timerExpired, wait)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
debounced.cancel = cancel
|
||||||
|
debounced.flush = flush
|
||||||
|
debounced.pending = pending
|
||||||
|
return debounced
|
||||||
|
}
|
||||||
|
|
||||||
|
export default debounce
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
/** Detect free variable `global` from Node.js. */
|
||||||
|
const freeGlobal = typeof global === 'object' && global !== null && global.Object === Object && global
|
||||||
|
|
||||||
|
export default freeGlobal
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-09-01 21:42:32
|
||||||
|
* @LastEditTime: 2023-09-03 11:43:06
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\common\lodash\internal\root.ts
|
||||||
|
* 记得注释
|
||||||
|
*/
|
||||||
|
import freeGlobal from './freeGlobal'
|
||||||
|
|
||||||
|
/** Detect free variable `globalThis` */
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
|
const freeGlobalThis = typeof globalThis === 'object' && globalThis !== null && globalThis.Object == Object && globalThis
|
||||||
|
|
||||||
|
/** Detect free variable `self`. */
|
||||||
|
const freeSelf = typeof self === 'object' && self !== null && self.Object === Object && self
|
||||||
|
|
||||||
|
/** Used as a reference to the global object. */
|
||||||
|
// eslint-disable-next-line no-new-func
|
||||||
|
const root = freeGlobalThis || freeGlobal || freeSelf || Function('return this')()
|
||||||
|
|
||||||
|
export default root
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Checks if `value` is the
|
||||||
|
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
|
||||||
|
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
||||||
|
*
|
||||||
|
* @since 0.1.0
|
||||||
|
* @category Lang
|
||||||
|
* @param {*} value The value to check.
|
||||||
|
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* isObject({})
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* isObject([1, 2, 3])
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* isObject(Function)
|
||||||
|
* // => true
|
||||||
|
*
|
||||||
|
* isObject(null)
|
||||||
|
* // => false
|
||||||
|
*/
|
||||||
|
function isObject(value) {
|
||||||
|
const type = typeof value
|
||||||
|
return value != null && (type === 'object' || type === 'function')
|
||||||
|
}
|
||||||
|
|
||||||
|
export default isObject
|
||||||
@ -0,0 +1,159 @@
|
|||||||
|
import { ref, computed, onBeforeUnmount } from 'vue'
|
||||||
|
import { isDef } from '../common/util'
|
||||||
|
|
||||||
|
// 定义倒计时时间的数据结构
|
||||||
|
export type CurrentTime = {
|
||||||
|
days: number
|
||||||
|
hours: number
|
||||||
|
total: number
|
||||||
|
minutes: number
|
||||||
|
seconds: number
|
||||||
|
milliseconds: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义倒计时的配置项
|
||||||
|
export type UseCountDownOptions = {
|
||||||
|
time: number // 倒计时总时间,单位为毫秒
|
||||||
|
millisecond?: boolean // 是否开启毫秒级倒计时,默认为 false
|
||||||
|
onChange?: (current: CurrentTime) => void // 倒计时每次变化时的回调函数
|
||||||
|
onFinish?: () => void // 倒计时结束时的回调函数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义常量
|
||||||
|
const SECOND = 1000
|
||||||
|
const MINUTE = 60 * SECOND
|
||||||
|
const HOUR = 60 * MINUTE
|
||||||
|
const DAY = 24 * HOUR
|
||||||
|
|
||||||
|
// 将时间转换为倒计时数据结构
|
||||||
|
function parseTime(time: number): CurrentTime {
|
||||||
|
const days = Math.floor(time / DAY)
|
||||||
|
const hours = Math.floor((time % DAY) / HOUR)
|
||||||
|
const minutes = Math.floor((time % HOUR) / MINUTE)
|
||||||
|
const seconds = Math.floor((time % MINUTE) / SECOND)
|
||||||
|
const milliseconds = Math.floor(time % SECOND)
|
||||||
|
|
||||||
|
return {
|
||||||
|
total: time,
|
||||||
|
days,
|
||||||
|
hours,
|
||||||
|
minutes,
|
||||||
|
seconds,
|
||||||
|
milliseconds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断两个时间是否在同一秒内
|
||||||
|
function isSameSecond(time1: number, time2: number): boolean {
|
||||||
|
return Math.floor(time1 / 1000) === Math.floor(time2 / 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断当前环境是否为 H5
|
||||||
|
const isH5 = process.env.UNI_PLATFORM === 'h5'
|
||||||
|
|
||||||
|
// 封装 requestAnimationFrame 和 setTimeout
|
||||||
|
function raf(fn: FrameRequestCallback): number {
|
||||||
|
return isH5 ? requestAnimationFrame(fn) : setTimeout(fn, 33)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelRaf(id: number) {
|
||||||
|
if (isH5) {
|
||||||
|
cancelAnimationFrame(id)
|
||||||
|
} else {
|
||||||
|
clearTimeout(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义 useCountDown 函数
|
||||||
|
export function useCountDown(options: UseCountDownOptions) {
|
||||||
|
let timer: number | null = null // 定时器
|
||||||
|
let endTime: number // 结束时间
|
||||||
|
let counting: boolean // 是否计时中
|
||||||
|
|
||||||
|
const remain = ref(options.time) // 剩余时间
|
||||||
|
const current = computed(() => parseTime(remain.value)) // 当前倒计时数据
|
||||||
|
|
||||||
|
// 暂停倒计时
|
||||||
|
const pause = () => {
|
||||||
|
counting = false
|
||||||
|
cancelRaf(timer!)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前剩余时间
|
||||||
|
const getCurrentRemain = () => Math.max(endTime - Date.now(), 0)
|
||||||
|
|
||||||
|
// 设置剩余时间
|
||||||
|
const setRemain = (value: number) => {
|
||||||
|
remain.value = value
|
||||||
|
isDef(options.onChange) && options.onChange(current.value)
|
||||||
|
|
||||||
|
if (value === 0) {
|
||||||
|
pause()
|
||||||
|
isDef(options.onFinish) && options.onFinish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每毫秒更新一次倒计时
|
||||||
|
const microTick = () => {
|
||||||
|
timer = raf(() => {
|
||||||
|
if (counting) {
|
||||||
|
setRemain(getCurrentRemain())
|
||||||
|
|
||||||
|
if (remain.value > 0) {
|
||||||
|
microTick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每秒更新一次倒计时
|
||||||
|
const macroTick = () => {
|
||||||
|
timer = raf(() => {
|
||||||
|
if (counting) {
|
||||||
|
const remainRemain = getCurrentRemain()
|
||||||
|
|
||||||
|
if (!isSameSecond(remainRemain, remain.value) || remainRemain === 0) {
|
||||||
|
setRemain(remainRemain)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remain.value > 0) {
|
||||||
|
macroTick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据配置项选择更新方式
|
||||||
|
const tick = () => {
|
||||||
|
if (options.millisecond) {
|
||||||
|
microTick()
|
||||||
|
} else {
|
||||||
|
macroTick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始倒计时
|
||||||
|
const start = () => {
|
||||||
|
if (!counting) {
|
||||||
|
endTime = Date.now() + remain.value
|
||||||
|
counting = true
|
||||||
|
tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置倒计时
|
||||||
|
const reset = (totalTime: number = options.time) => {
|
||||||
|
pause()
|
||||||
|
remain.value = totalTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在组件卸载前暂停倒计时
|
||||||
|
onBeforeUnmount(pause)
|
||||||
|
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
pause,
|
||||||
|
reset,
|
||||||
|
current
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import { ref, watch } from 'vue'
|
||||||
|
|
||||||
|
function useLockScroll(shouldLock: () => boolean) {
|
||||||
|
const scrollLockCount = ref(0)
|
||||||
|
|
||||||
|
const lock = () => {
|
||||||
|
if (scrollLockCount.value === 0) {
|
||||||
|
document.getElementsByTagName('body')[0].style.overflow = 'hidden'
|
||||||
|
}
|
||||||
|
scrollLockCount.value++
|
||||||
|
}
|
||||||
|
|
||||||
|
const unlock = () => {
|
||||||
|
if (scrollLockCount.value > 0) {
|
||||||
|
scrollLockCount.value--
|
||||||
|
if (scrollLockCount.value === 0) {
|
||||||
|
document.getElementsByTagName('body')[0].style.overflow = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(shouldLock, (value) => {
|
||||||
|
value ? lock() : unlock()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
lock,
|
||||||
|
unlock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useLockScroll
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import { ref, inject, computed, onUnmounted, InjectionKey, getCurrentInstance, ComponentPublicInstance, ComponentInternalInstance } from 'vue'
|
||||||
|
|
||||||
|
type ParentProvide<T> = T & {
|
||||||
|
link(child: ComponentInternalInstance): void
|
||||||
|
unlink(child: ComponentInternalInstance): void
|
||||||
|
children: ComponentPublicInstance[]
|
||||||
|
internalChildren: ComponentInternalInstance[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useParent<T>(key: InjectionKey<ParentProvide<T>>) {
|
||||||
|
const parent = inject(key, null)
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
const instance = getCurrentInstance()!
|
||||||
|
const { link, unlink, internalChildren } = parent
|
||||||
|
|
||||||
|
link(instance)
|
||||||
|
onUnmounted(() => unlink(instance))
|
||||||
|
|
||||||
|
const index = computed(() => internalChildren.indexOf(instance))
|
||||||
|
|
||||||
|
return {
|
||||||
|
parent,
|
||||||
|
index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
parent: null,
|
||||||
|
index: ref(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,168 @@
|
|||||||
|
import { getCurrentInstance, ref } from 'vue'
|
||||||
|
import { getRect } from '../common/util'
|
||||||
|
|
||||||
|
export function usePopover() {
|
||||||
|
const { proxy } = getCurrentInstance() as any
|
||||||
|
const popStyle = ref<string>('')
|
||||||
|
const arrowStyle = ref<string>('')
|
||||||
|
const showStyle = ref<string>('')
|
||||||
|
const arrowClass = ref<string>('')
|
||||||
|
const popWidth = ref<number>(0)
|
||||||
|
const popHeight = ref<number>(0)
|
||||||
|
const left = ref<number>(0)
|
||||||
|
const bottom = ref<number>(0)
|
||||||
|
const width = ref<number>(0)
|
||||||
|
const height = ref<number>(0)
|
||||||
|
const top = ref<number>(0)
|
||||||
|
|
||||||
|
function noop() {}
|
||||||
|
|
||||||
|
function init(
|
||||||
|
placement:
|
||||||
|
| 'top'
|
||||||
|
| 'top-start'
|
||||||
|
| 'top-end'
|
||||||
|
| 'bottom'
|
||||||
|
| 'bottom-start'
|
||||||
|
| 'bottom-end'
|
||||||
|
| 'left'
|
||||||
|
| 'left-start'
|
||||||
|
| 'left-end'
|
||||||
|
| 'right'
|
||||||
|
| 'right-start'
|
||||||
|
| 'right-end',
|
||||||
|
visibleArrow: boolean,
|
||||||
|
selector: string
|
||||||
|
) {
|
||||||
|
// 初始化 class
|
||||||
|
if (visibleArrow) {
|
||||||
|
const arrowClassArr = [
|
||||||
|
`wd-${selector}__arrow`,
|
||||||
|
placement === 'bottom' || placement === 'bottom-start' || placement === 'bottom-end' ? `wd-${selector}__arrow-up` : '',
|
||||||
|
placement === 'left' || placement === 'left-start' || placement === 'left-end' ? `wd-${selector}__arrow-right` : '',
|
||||||
|
placement === 'right' || placement === 'right-start' || placement === 'right-end' ? `wd-${selector}__arrow-left` : '',
|
||||||
|
placement === 'top' || placement === 'top-start' || placement === 'top-end' ? `wd-${selector}__arrow-down` : ''
|
||||||
|
]
|
||||||
|
arrowClass.value = arrowClassArr.join(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化数据获取
|
||||||
|
getRect('#target', false, proxy).then((rect: any) => {
|
||||||
|
if (!rect) return
|
||||||
|
left.value = rect.left
|
||||||
|
bottom.value = rect.bottom
|
||||||
|
width.value = rect.width
|
||||||
|
height.value = rect.height
|
||||||
|
top.value = rect.top
|
||||||
|
})
|
||||||
|
// 用透明度可在初始化时获取到pop尺寸
|
||||||
|
getRect('#pos', false, proxy).then((rect: any) => {
|
||||||
|
if (!rect) return
|
||||||
|
popWidth.value = rect.width
|
||||||
|
popHeight.value = rect.height
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkType(value) {
|
||||||
|
return Object.prototype.toString.call(value).slice(8, -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function control(
|
||||||
|
placement:
|
||||||
|
| 'top'
|
||||||
|
| 'top-start'
|
||||||
|
| 'top-end'
|
||||||
|
| 'bottom'
|
||||||
|
| 'bottom-start'
|
||||||
|
| 'bottom-end'
|
||||||
|
| 'left'
|
||||||
|
| 'left-start'
|
||||||
|
| 'left-end'
|
||||||
|
| 'right'
|
||||||
|
| 'right-start'
|
||||||
|
| 'right-end',
|
||||||
|
offset: number
|
||||||
|
) {
|
||||||
|
// arrow size
|
||||||
|
const arrowSize = 9
|
||||||
|
// 上下位(纵轴)对应的距离左边的距离
|
||||||
|
const verticalX = width.value / 2
|
||||||
|
// 上下位(纵轴)对应的距离底部的距离
|
||||||
|
const verticalY = arrowSize + height.value + 5
|
||||||
|
// 左右位(横轴)对应的距离左边的距离
|
||||||
|
const horizontalX = width.value + arrowSize + 5
|
||||||
|
// 左右位(横轴)对应的距离底部的距离
|
||||||
|
const horizontalY = height.value / 2
|
||||||
|
|
||||||
|
const offsetX = (verticalX - 17 > 0 ? 0 : verticalX - 25) + offset
|
||||||
|
const offsetY = (horizontalY - 17 > 0 ? 0 : horizontalY - 25) + offset
|
||||||
|
|
||||||
|
const placements = new Map([
|
||||||
|
// 上
|
||||||
|
['top', [`left: ${verticalX}px; bottom: ${verticalY}px; transform: translateX(-50%);`, 'left: 50%;']],
|
||||||
|
[
|
||||||
|
'top-start',
|
||||||
|
[
|
||||||
|
`left: ${offsetX}px; bottom: ${verticalY}px;`,
|
||||||
|
`left: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px;`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'top-end',
|
||||||
|
[
|
||||||
|
`right: ${offsetX}px; bottom: ${verticalY}px;`,
|
||||||
|
`right: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px; transform: translateX(50%);`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// 下
|
||||||
|
['bottom', [`left: ${verticalX}px; top: ${verticalY}px; transform: translateX(-50%);`, 'left: 50%;']],
|
||||||
|
[
|
||||||
|
'bottom-start',
|
||||||
|
[`left: ${offsetX}px; top: ${verticalY}px;`, `left: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px;`]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'bottom-end',
|
||||||
|
[
|
||||||
|
`right: ${offsetX}px; top: ${verticalY}px;`,
|
||||||
|
`right: ${(popWidth.value >= width.value ? width.value / 2 : popWidth.value - 25) - offsetX}px; transform: translateX(50%);`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// 左
|
||||||
|
['left', [`right: ${horizontalX}px; top: ${horizontalY}px; transform: translateY(-50%);`, 'top: 50%']],
|
||||||
|
[
|
||||||
|
'left-start',
|
||||||
|
[
|
||||||
|
`right: ${horizontalX}px; top: ${offsetY}px;`,
|
||||||
|
`top: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px;`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'left-end',
|
||||||
|
[
|
||||||
|
`right: ${horizontalX}px; bottom: ${offsetY}px;`,
|
||||||
|
`bottom: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px; transform: translateY(50%);`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// 右
|
||||||
|
['right', [`left: ${horizontalX}px; top: ${horizontalY}px; transform: translateY(-50%);`, 'top: 50%']],
|
||||||
|
[
|
||||||
|
'right-start',
|
||||||
|
[
|
||||||
|
`left: ${horizontalX}px; top: ${offsetY}px;`,
|
||||||
|
`top: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px;`
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'right-end',
|
||||||
|
[
|
||||||
|
`left: ${horizontalX}px; bottom: ${offsetY}px;`,
|
||||||
|
`bottom: ${(popHeight.value >= height.value ? height.value / 2 : popHeight.value - 20) - offsetY}px; transform: translateY(50%);`
|
||||||
|
]
|
||||||
|
]
|
||||||
|
])
|
||||||
|
popStyle.value = placements.get(placement)![0]
|
||||||
|
arrowStyle.value = placements.get(placement)![1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return { popStyle, arrowStyle, showStyle, arrowClass, init, control, noop, checkType }
|
||||||
|
}
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
import { type Ref, provide, ref } from 'vue'
|
||||||
|
|
||||||
|
export const queueKey = '__QUEUE_KEY__'
|
||||||
|
|
||||||
|
export interface Queue {
|
||||||
|
queue: Ref<any[]>
|
||||||
|
pushToQueue: (comp: any) => void
|
||||||
|
removeFromQueue: (comp: any) => void
|
||||||
|
closeOther: (comp: any) => void
|
||||||
|
closeOutside: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useQueue() {
|
||||||
|
const queue = ref<any[]>([])
|
||||||
|
|
||||||
|
function pushToQueue(comp: any) {
|
||||||
|
queue.value.push(comp)
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFromQueue(comp: any) {
|
||||||
|
queue.value = queue.value.filter((item) => {
|
||||||
|
return item.$.uid !== comp.$.uid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOther(comp: any) {
|
||||||
|
queue.value.forEach((item) => {
|
||||||
|
if (item.$.uid !== comp.$.uid) {
|
||||||
|
item.$.exposed.close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOutside() {
|
||||||
|
queue.value.forEach((item) => {
|
||||||
|
item.$.exposed.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
provide(queueKey, {
|
||||||
|
queue,
|
||||||
|
pushToQueue,
|
||||||
|
removeFromQueue,
|
||||||
|
closeOther,
|
||||||
|
closeOutside
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
closeOther,
|
||||||
|
closeOutside
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
export function useTouch() {
|
||||||
|
const direction = ref<string>('')
|
||||||
|
const deltaX = ref<number>(0)
|
||||||
|
const deltaY = ref<number>(0)
|
||||||
|
const offsetX = ref<number>(0)
|
||||||
|
const offsetY = ref<number>(0)
|
||||||
|
const startX = ref<number>(0)
|
||||||
|
const startY = ref<number>(0)
|
||||||
|
|
||||||
|
function touchStart(event) {
|
||||||
|
const touch = event.touches[0]
|
||||||
|
direction.value = ''
|
||||||
|
deltaX.value = 0
|
||||||
|
deltaY.value = 0
|
||||||
|
offsetX.value = 0
|
||||||
|
offsetY.value = 0
|
||||||
|
startX.value = touch.clientX
|
||||||
|
startY.value = touch.clientY
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchMove(event) {
|
||||||
|
const touch = event.touches[0]
|
||||||
|
deltaX.value = touch.clientX - startX.value
|
||||||
|
deltaY.value = touch.clientY - startY.value
|
||||||
|
offsetX.value = Math.abs(deltaX.value)
|
||||||
|
offsetY.value = Math.abs(deltaY.value)
|
||||||
|
direction.value = offsetX.value > offsetY.value ? 'horizontal' : offsetX.value < offsetY.value ? 'vertical' : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
touchStart,
|
||||||
|
touchMove,
|
||||||
|
direction,
|
||||||
|
deltaX,
|
||||||
|
deltaY,
|
||||||
|
offsetX,
|
||||||
|
offsetY,
|
||||||
|
startX,
|
||||||
|
startY
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,194 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(action-sheet) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include e(action) {
|
||||||
|
color: $-dark-color;
|
||||||
|
background: $-dark-background2;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $-dark-background4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(subname) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(cancel) {
|
||||||
|
color: $-dark-color;
|
||||||
|
background: $-dark-background4;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $-dark-background5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-action-sheet__close) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(panel-title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(header) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-action-sheet__popup){
|
||||||
|
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(action-sheet) {
|
||||||
|
background-color: $-color-white;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
|
||||||
|
@include edeep(popup) {
|
||||||
|
border-radius: $-action-sheet-radius $-action-sheet-radius 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(actions) {
|
||||||
|
padding: 8px 0;
|
||||||
|
max-height: 50vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(action) {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: $-action-sheet-action-height;
|
||||||
|
line-height: $-action-sheet-action-height;
|
||||||
|
color: $-action-sheet-color;
|
||||||
|
font-size: $-action-sheet-fs;
|
||||||
|
text-align: center;
|
||||||
|
border: none;
|
||||||
|
background: $-action-sheet-bg;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $-action-sheet-active-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(disabled) {
|
||||||
|
color: $-action-sheet-disabled-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(loading) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(name) {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(subname) {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 4px;
|
||||||
|
font-size: $-action-sheet-subname-fs;
|
||||||
|
color: $-action-sheet-subname-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(cancel) {
|
||||||
|
display: block;
|
||||||
|
width: calc(100% - 48px);
|
||||||
|
line-height: $-action-sheet-cancel-height;
|
||||||
|
padding: 0;
|
||||||
|
color: $-action-sheet-cancel-color;
|
||||||
|
font-size: $-action-sheet-fs;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: $-action-sheet-cancel-radius;
|
||||||
|
border: none;
|
||||||
|
background: $-action-sheet-cancel-bg;
|
||||||
|
outline: none;
|
||||||
|
margin: 0 auto 24px;
|
||||||
|
font-weight: $-action-sheet-weight;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: $-action-sheet-active-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(header) {
|
||||||
|
color: $-action-sheet-color;
|
||||||
|
position: relative;
|
||||||
|
height: $-action-sheet-title-height;
|
||||||
|
line-height: $-action-sheet-title-height;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $-action-sheet-title-fs;
|
||||||
|
font-weight: $-action-sheet-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(close) {
|
||||||
|
position: absolute;
|
||||||
|
top: $-action-sheet-close-top;
|
||||||
|
right: $-action-sheet-close-right;
|
||||||
|
color: $-action-sheet-close-color;
|
||||||
|
font-size: $-action-sheet-close-fs;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(panels) {
|
||||||
|
height: 84px;
|
||||||
|
overflow-y: hidden;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(panels-content) {
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(panel) {
|
||||||
|
width: 88px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: inline-block;
|
||||||
|
padding: $-action-sheet-panel-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(panel-img) {
|
||||||
|
display: block;
|
||||||
|
width: $-action-sheet-panel-img-fs;
|
||||||
|
height: $-action-sheet-panel-img-fs;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 7px;
|
||||||
|
border-radius: $-action-sheet-panel-img-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(panel-title) {
|
||||||
|
font-size: $-action-sheet-subname-fs;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
color: $-action-sheet-color;
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<wd-popup
|
||||||
|
custom-class="wd-action-sheet__popup"
|
||||||
|
:custom-style="`${(actions && actions.length) || (panels && panels.length) ? 'background: transparent;' : ''}`"
|
||||||
|
v-model="showPopup"
|
||||||
|
:duration="duration"
|
||||||
|
position="bottom"
|
||||||
|
:close-on-click-modal="closeOnClickModal"
|
||||||
|
:safe-area-inset-bottom="safeAreaInsetBottom"
|
||||||
|
:lazy-render="lazyRender"
|
||||||
|
@enter="handleOpen"
|
||||||
|
@close="close"
|
||||||
|
@after-enter="handleOpened"
|
||||||
|
@after-leave="handleClosed"
|
||||||
|
@click-modal="handleClickModal"
|
||||||
|
:z-index="zIndex"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
:class="`wd-action-sheet ${customClass}`"
|
||||||
|
:style="`${
|
||||||
|
(actions && actions.length) || (panels && panels.length)
|
||||||
|
? 'margin: 0 10px calc(var(--window-bottom) + 10px) 10px; border-radius: 16px;'
|
||||||
|
: 'margin-bottom: var(--window-bottom);'
|
||||||
|
} ${customStyle}`"
|
||||||
|
>
|
||||||
|
<view v-if="title" :class="`wd-action-sheet__header ${customHeaderClass}`">
|
||||||
|
{{ title }}
|
||||||
|
<wd-icon custom-class="wd-action-sheet__close" name="add" @click="close" />
|
||||||
|
</view>
|
||||||
|
<view class="wd-action-sheet__actions" v-if="actions && actions.length">
|
||||||
|
<button
|
||||||
|
v-for="(action, rowIndex) in actions"
|
||||||
|
:key="rowIndex"
|
||||||
|
:class="`wd-action-sheet__action ${action.disabled ? 'wd-action-sheet__action--disabled' : ''} ${
|
||||||
|
action.loading ? 'wd-action-sheet__action--loading' : ''
|
||||||
|
}`"
|
||||||
|
:style="`color: ${action.color}`"
|
||||||
|
@click="select(rowIndex, 'action')"
|
||||||
|
>
|
||||||
|
<wd-loading v-if="action.loading" size="20px" />
|
||||||
|
<view v-else class="wd-action-sheet__name">{{ action.name }}</view>
|
||||||
|
<view v-if="!action.loading && action.subname" class="wd-action-sheet__subname">{{ action.subname }}</view>
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
<view v-if="formatPanels && formatPanels.length">
|
||||||
|
<view v-for="(panel, rowIndex) in formatPanels" :key="rowIndex" class="wd-action-sheet__panels">
|
||||||
|
<view class="wd-action-sheet__panels-content">
|
||||||
|
<view v-for="(col, colIndex) in panel" :key="colIndex" class="wd-action-sheet__panel" @click="select(rowIndex, 'panels', colIndex)">
|
||||||
|
<image class="wd-action-sheet__panel-img" :src="(col as any).iconUrl" />
|
||||||
|
<view class="wd-action-sheet__panel-title">{{ (col as any).title }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot />
|
||||||
|
<button v-if="cancelText" class="wd-action-sheet__cancel" @click="handleCancel">{{ cancelText }}</button>
|
||||||
|
</view>
|
||||||
|
</wd-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-action-sheet',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { watch, ref } from 'vue'
|
||||||
|
|
||||||
|
interface Action {
|
||||||
|
// 选项名称
|
||||||
|
name: string
|
||||||
|
// 描述信息
|
||||||
|
subname: string
|
||||||
|
// 颜色
|
||||||
|
color: string
|
||||||
|
// 禁用
|
||||||
|
disabled: boolean
|
||||||
|
// 加载中状态
|
||||||
|
loading: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Panel {
|
||||||
|
// 图片地址
|
||||||
|
iconUrl: string
|
||||||
|
// 标题内容
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
customClass?: string
|
||||||
|
customHeaderClass?: string
|
||||||
|
customStyle?: string
|
||||||
|
modelValue: boolean
|
||||||
|
actions?: Array<Action>
|
||||||
|
panels?: Array<Panel>
|
||||||
|
title?: string
|
||||||
|
cancelText?: string
|
||||||
|
closeOnClickAction?: boolean
|
||||||
|
closeOnClickModal?: boolean
|
||||||
|
duration?: number
|
||||||
|
zIndex?: number
|
||||||
|
lazyRender?: boolean
|
||||||
|
safeAreaInsetBottom?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
customClass: '',
|
||||||
|
customHeaderClass: '',
|
||||||
|
customStyle: '',
|
||||||
|
modelValue: false,
|
||||||
|
actions: () => [] as Array<Action>,
|
||||||
|
panels: () => [] as Array<Panel>,
|
||||||
|
closeOnClickAction: true,
|
||||||
|
closeOnClickModal: true,
|
||||||
|
duration: 200,
|
||||||
|
zIndex: 10,
|
||||||
|
lazyRender: true,
|
||||||
|
safeAreaInsetBottom: true
|
||||||
|
})
|
||||||
|
const formatPanels = ref<Array<Panel> | Array<Array<Panel>>>([])
|
||||||
|
|
||||||
|
const showPopup = ref<boolean>(false)
|
||||||
|
|
||||||
|
watch(() => props.panels, computedValue, { deep: true, immediate: true })
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(newValue) => {
|
||||||
|
showPopup.value = newValue
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits(['select', 'click-modal', 'cancel', 'closed', 'close', 'open', 'opened', 'update:modelValue'])
|
||||||
|
|
||||||
|
function isArray() {
|
||||||
|
return props.panels.length && !(props.panels[0] instanceof Array)
|
||||||
|
}
|
||||||
|
function computedValue() {
|
||||||
|
formatPanels.value = isArray() ? [props.panels] : props.panels
|
||||||
|
}
|
||||||
|
|
||||||
|
function select(rowIndex: number, type: 'action' | 'panels', colIndex?: number) {
|
||||||
|
if (type === 'action') {
|
||||||
|
emit('select', {
|
||||||
|
item: props.actions[rowIndex],
|
||||||
|
index: rowIndex
|
||||||
|
})
|
||||||
|
} else if (isArray()) {
|
||||||
|
emit('select', {
|
||||||
|
item: props.panels[Number(colIndex)],
|
||||||
|
index: colIndex
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
emit('select', {
|
||||||
|
item: props.panels[rowIndex][Number(colIndex)],
|
||||||
|
rowIndex,
|
||||||
|
colIndex
|
||||||
|
})
|
||||||
|
}
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
function handleClickModal() {
|
||||||
|
emit('click-modal')
|
||||||
|
if (props.closeOnClickModal) {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleCancel() {
|
||||||
|
emit('cancel')
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
function close() {
|
||||||
|
emit('update:modelValue', false)
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
function handleOpen() {
|
||||||
|
emit('open')
|
||||||
|
}
|
||||||
|
function handleOpened() {
|
||||||
|
emit('opened')
|
||||||
|
}
|
||||||
|
function handleClosed() {
|
||||||
|
emit('closed')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
@import './../common/abstracts/_mixin.scss';
|
||||||
|
@import './../common/abstracts/variable.scss';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(badge) {
|
||||||
|
@include e(content) {
|
||||||
|
border-color: $-dark-background2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include b(badge) {
|
||||||
|
position: relative;
|
||||||
|
vertical-align: middle;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
@include e(content) {
|
||||||
|
display: inline-block;
|
||||||
|
height: $-badge-height;
|
||||||
|
line-height: $-badge-height;
|
||||||
|
padding: $-badge-padding;
|
||||||
|
background-color: $-badge-bg;
|
||||||
|
border-radius: calc($-badge-height / 2 + 2px);
|
||||||
|
color: $-badge-color;
|
||||||
|
font-size: $-badge-fs;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
border: $-badge-border;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
@include when(fixed) {
|
||||||
|
position: absolute;
|
||||||
|
transform: translateY(-50%) translateX(50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(dot) {
|
||||||
|
height: $-badge-dot-size;
|
||||||
|
width: $-badge-dot-size;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@each $type in (primary, success, warning, info, danger) {
|
||||||
|
@include m($type) {
|
||||||
|
@if $type == primary {
|
||||||
|
background-color: $-badge-primary;
|
||||||
|
} @else if $type == success {
|
||||||
|
background-color: $-badge-success;
|
||||||
|
} @else if $type == warning {
|
||||||
|
background-color: $-badge-warning;
|
||||||
|
} @else if $type == info {
|
||||||
|
background-color: $-badge-info;
|
||||||
|
} @else {
|
||||||
|
background-color: $-badge-danger;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-06-12 18:40:59
|
||||||
|
* @LastEditTime: 2023-11-22 13:11:29
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-badge\wd-badge.vue
|
||||||
|
* 记得注释
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view :class="['wd-badge', customClass]" :style="customStyle">
|
||||||
|
<slot></slot>
|
||||||
|
<view
|
||||||
|
v-if="isBadgeShow"
|
||||||
|
:class="['wd-badge__content', 'is-fixed', type ? 'wd-badge__content--' + type : '', isDot ? 'is-dot' : '']"
|
||||||
|
:style="contentStyle"
|
||||||
|
>
|
||||||
|
{{ content }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-badge',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from 'vue'
|
||||||
|
type BadgeType = 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
||||||
|
interface Props {
|
||||||
|
modelValue?: number | string | null
|
||||||
|
/** 当数值为 0 时,是否展示徽标 */
|
||||||
|
showZero?: boolean
|
||||||
|
bgColor?: string
|
||||||
|
max?: number
|
||||||
|
isDot?: boolean
|
||||||
|
hidden?: boolean
|
||||||
|
type?: BadgeType
|
||||||
|
top?: number
|
||||||
|
right?: number
|
||||||
|
customClass?: string
|
||||||
|
customStyle?: string
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
customClass: '',
|
||||||
|
customStyle: '',
|
||||||
|
modelValue: null,
|
||||||
|
showZero: false
|
||||||
|
})
|
||||||
|
const content = ref<number | string | null>(null)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[() => props.modelValue, () => props.max, () => props.isDot],
|
||||||
|
() => {
|
||||||
|
notice()
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const contentStyle = computed(() => {
|
||||||
|
return `background-color: ${props.bgColor};top:${props.top || 0}px;right:${props.right || 0}px`
|
||||||
|
})
|
||||||
|
|
||||||
|
// 是否展示徽标数字
|
||||||
|
const isBadgeShow = computed(() => {
|
||||||
|
let isBadgeShow: boolean = false
|
||||||
|
if (!props.hidden && (content.value || (content.value === 0 && props.showZero) || props.isDot)) {
|
||||||
|
isBadgeShow = true
|
||||||
|
}
|
||||||
|
return isBadgeShow
|
||||||
|
})
|
||||||
|
|
||||||
|
function notice() {
|
||||||
|
if (props.isDot) return
|
||||||
|
let value = props.modelValue
|
||||||
|
const max = props.max
|
||||||
|
if (value && max && typeof value === 'number' && !Number.isNaN(value) && !Number.isNaN(max)) {
|
||||||
|
value = max < value ? `${max}+` : value
|
||||||
|
}
|
||||||
|
content.value = value
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script></script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,190 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
hover-class="wd-button--active"
|
||||||
|
:style="customStyle"
|
||||||
|
:class="[
|
||||||
|
'wd-button',
|
||||||
|
'is-' + type,
|
||||||
|
'is-' + size,
|
||||||
|
plain ? 'is-plain' : '',
|
||||||
|
disabled ? 'is-disabled' : '',
|
||||||
|
round ? 'is-round' : '',
|
||||||
|
suck ? 'is-suck' : '',
|
||||||
|
block ? 'is-block' : '',
|
||||||
|
loading ? 'is-loading' : '',
|
||||||
|
customClass
|
||||||
|
]"
|
||||||
|
:hover-start-time="hoverStartTime"
|
||||||
|
:hover-stay-time="hoverStayTime"
|
||||||
|
:open-type="openType"
|
||||||
|
:send-message-title="sendMessageTitle"
|
||||||
|
:send-message-path="sendMessagePath"
|
||||||
|
:send-message-img="sendMessageImg"
|
||||||
|
:app-parameter="appParameter"
|
||||||
|
:show-message-card="showMessageCard"
|
||||||
|
:session-from="sessionFrom"
|
||||||
|
:lang="lang"
|
||||||
|
:hover-stop-propagation="hoverStopPropagation"
|
||||||
|
:form-type="formType"
|
||||||
|
@click="handleClick"
|
||||||
|
@getuserinfo="handleGetuserinfo"
|
||||||
|
@contact="handleConcat"
|
||||||
|
@getphonenumber="handleGetphonenumber"
|
||||||
|
@error="handleError"
|
||||||
|
@launchapp="handleLaunchapp"
|
||||||
|
@opensetting="handleOpensetting"
|
||||||
|
>
|
||||||
|
<view v-if="loading" class="wd-button__loading">
|
||||||
|
<view class="wd-button__loading-svg" :style="loadingStyle"></view>
|
||||||
|
</view>
|
||||||
|
<wd-icon v-if="icon" custom-class="wd-button__icon" :name="icon"></wd-icon>
|
||||||
|
<view class="wd-button__text"><slot /></view>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-button',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, watch } from 'vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import base64 from '../common/base64'
|
||||||
|
|
||||||
|
const loadingIcon = (color = '#4D80F0', reverse = true) => {
|
||||||
|
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 42 42"><defs><linearGradient x1="100%" y1="0%" x2="0%" y2="0%" id="a"><stop stop-color="${
|
||||||
|
reverse ? color : '#fff'
|
||||||
|
}" offset="0%" stop-opacity="0"/><stop stop-color="${
|
||||||
|
reverse ? color : '#fff'
|
||||||
|
}" offset="100%"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><path d="M21 1c11.046 0 20 8.954 20 20s-8.954 20-20 20S1 32.046 1 21 9.954 1 21 1zm0 7C13.82 8 8 13.82 8 21s5.82 13 13 13 13-5.82 13-13S28.18 8 21 8z" fill="${
|
||||||
|
reverse ? '#fff' : color
|
||||||
|
}"/><path d="M4.599 21c0 9.044 7.332 16.376 16.376 16.376 9.045 0 16.376-7.332 16.376-16.376" stroke="url(#a)" stroke-width="3.5" stroke-linecap="round"/></g></svg>`
|
||||||
|
}
|
||||||
|
type ButtonType = 'primary' | 'success' | 'info' | 'warning' | 'error' | 'default' | 'text' | 'icon'
|
||||||
|
type ButtonSize = 'small' | 'medium' | 'large'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
plain?: boolean
|
||||||
|
disabled?: boolean
|
||||||
|
round?: boolean
|
||||||
|
suck?: boolean
|
||||||
|
block?: boolean
|
||||||
|
type?: ButtonType
|
||||||
|
size?: ButtonSize
|
||||||
|
icon?: string
|
||||||
|
loading?: boolean
|
||||||
|
loadingColor?: string
|
||||||
|
openType?: string
|
||||||
|
formType?: string
|
||||||
|
hoverStopPropagation?: boolean
|
||||||
|
lang?: string
|
||||||
|
sessionFrom?: string
|
||||||
|
sendMessageTitle?: string
|
||||||
|
sendMessagePath?: string
|
||||||
|
sendMessageImg?: string
|
||||||
|
appParameter?: string
|
||||||
|
showMessageCard?: boolean
|
||||||
|
customClass?: string
|
||||||
|
customStyle?: string
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
type: 'primary',
|
||||||
|
size: 'medium',
|
||||||
|
round: true,
|
||||||
|
plain: false,
|
||||||
|
loading: false,
|
||||||
|
suck: false,
|
||||||
|
block: false,
|
||||||
|
disabled: false,
|
||||||
|
customClass: '',
|
||||||
|
customStyle: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const hoverStartTime = ref<number>(20)
|
||||||
|
const hoverStayTime = ref<number>(70)
|
||||||
|
const loadingIconSvg = ref<string>('')
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.loading,
|
||||||
|
() => {
|
||||||
|
buildLoadingSvg()
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const loadingStyle = computed(() => {
|
||||||
|
return `background-image: url(${loadingIconSvg.value});`
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['click', 'getuserinfo', 'contact', 'getphonenumber', 'error', 'launchapp', 'opensetting'])
|
||||||
|
|
||||||
|
function handleClick(event) {
|
||||||
|
if (!props.disabled && !props.loading) {
|
||||||
|
emit('click', event.detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGetuserinfo(event) {
|
||||||
|
emit('getuserinfo', event.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleConcat(event) {
|
||||||
|
emit('contact', event.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleGetphonenumber(event) {
|
||||||
|
emit('getphonenumber', event.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleError(event) {
|
||||||
|
emit('error', event.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLaunchapp(event) {
|
||||||
|
emit('launchapp', event.detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpensetting(event) {
|
||||||
|
emit('opensetting', event.detail)
|
||||||
|
}
|
||||||
|
function buildLoadingSvg() {
|
||||||
|
const { loadingColor, type, plain } = props
|
||||||
|
let color = loadingColor
|
||||||
|
if (!color) {
|
||||||
|
switch (type) {
|
||||||
|
case 'primary':
|
||||||
|
color = '#4D80F0'
|
||||||
|
break
|
||||||
|
case 'success':
|
||||||
|
color = '#34d19d'
|
||||||
|
break
|
||||||
|
case 'info':
|
||||||
|
color = '#333'
|
||||||
|
break
|
||||||
|
case 'warning':
|
||||||
|
color = '#f0883a'
|
||||||
|
break
|
||||||
|
case 'error':
|
||||||
|
color = '#fa4350'
|
||||||
|
break
|
||||||
|
case 'default':
|
||||||
|
color = '#333'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const svg = loadingIcon(color, !plain)
|
||||||
|
loadingIconSvg.value = `"data:image/svg+xml;base64,${base64(svg)}"`
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-06-12 10:04:19
|
||||||
|
* @LastEditTime: 2023-07-15 16:16:34
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-calendar-view\index.scss
|
||||||
|
* 记得注释
|
||||||
|
*/
|
||||||
@ -0,0 +1,151 @@
|
|||||||
|
@import '../../common/abstracts/variable';
|
||||||
|
@import '../../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(month) {
|
||||||
|
@include e(title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(days) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(day) {
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-month__day-text {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(month) {
|
||||||
|
@include e(title) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 45px;
|
||||||
|
font-size: $-calendar-panel-title-fs;
|
||||||
|
color: $-calendar-panel-title-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(days) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: $-calendar-day-fs;
|
||||||
|
color: $-calendar-day-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(day) {
|
||||||
|
position: relative;
|
||||||
|
width: 14.285%;
|
||||||
|
height: $-calendar-day-height;
|
||||||
|
line-height: $-calendar-day-height;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-month__day-text {
|
||||||
|
color: $-calendar-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(current) {
|
||||||
|
color: $-calendar-active-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(selected) {
|
||||||
|
.wd-month__day-container {
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(middle) {
|
||||||
|
.wd-month__day-container {
|
||||||
|
background: $-calendar-range-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(start) {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
height: $-calendar-day-height;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 50%;
|
||||||
|
background: $-calendar-range-color;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-without-end::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-month__day-container {
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(end) {
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
height: $-calendar-day-height;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 50%;
|
||||||
|
background: $-calendar-range-color;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-month__day-container {
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(same) {
|
||||||
|
.wd-month__day-container {
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(day-container) {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(day-text) {
|
||||||
|
font-weight: $-calendar-day-fw;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(day-top) {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-size: $-calendar-info-fs;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(day-bottom) {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-size: $-calendar-info-fs;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
@import '../../common/abstracts/variable';
|
||||||
|
@import '../../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(month-panel) {
|
||||||
|
@include e(title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(weeks) {
|
||||||
|
box-shadow: 0px 4px 8px 0 rgba(255, 255, 255, 0.02);
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(time-label) {
|
||||||
|
color: $-dark-color;
|
||||||
|
&::after{
|
||||||
|
background: $-dark-background4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(month-panel) {
|
||||||
|
font-size: $-calendar-fs;
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
padding: 5px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $-calendar-panel-title-fs;
|
||||||
|
color: $-calendar-panel-title-color;
|
||||||
|
padding: $-calendar-panel-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(weeks) {
|
||||||
|
display: flex;
|
||||||
|
height: $-calendar-week-height;
|
||||||
|
line-height: $-calendar-week-height;
|
||||||
|
box-shadow: 0px 4px 8px 0 rgba(0, 0, 0, 0.02);
|
||||||
|
color: $-calendar-week-color;
|
||||||
|
font-size: $-calendar-week-fs;
|
||||||
|
padding: $-calendar-panel-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(week) {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(container) {
|
||||||
|
padding: $-calendar-panel-padding;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(time) {
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0px -4px 8px 0px rgba(0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(time-label) {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
font-size: $-picker-column-fs;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 125px;
|
||||||
|
color: $-picker-column-color;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
height: 35px;
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: $-picker-column-select-bg;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(time-text) {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(time-picker) {
|
||||||
|
flex: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 月份信息
|
||||||
|
*/
|
||||||
|
export interface MonthInfo {
|
||||||
|
date: number
|
||||||
|
height: number
|
||||||
|
}
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
@import '../../common/abstracts/variable';
|
||||||
|
@import '../../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(year) {
|
||||||
|
@include e(title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(months) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(month) {
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-year__month-text {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(year) {
|
||||||
|
@include e(title) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 45px;
|
||||||
|
font-size: $-calendar-panel-title-fs;
|
||||||
|
color: $-calendar-panel-title-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(months) {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: $-calendar-day-fs;
|
||||||
|
color: $-calendar-day-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(month) {
|
||||||
|
position: relative;
|
||||||
|
width: 25%;
|
||||||
|
height: $-calendar-day-height;
|
||||||
|
line-height: $-calendar-day-height;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-year__month-text {
|
||||||
|
color: $-calendar-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(current) {
|
||||||
|
color: $-calendar-active-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(selected) {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.wd-year__month-text {
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(middle) {
|
||||||
|
background: $-calendar-range-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(start) {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
content: '';
|
||||||
|
background: $-calendar-range-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-year__month-text {
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-without-end::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(end) {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
content: '';
|
||||||
|
background: $-calendar-range-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-year__month-text {
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(same) {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.wd-year__month-text {
|
||||||
|
background: $-calendar-active-color;
|
||||||
|
border-radius: $-calendar-active-border;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(month-text) {
|
||||||
|
width: $-calendar-month-width;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(month-top) {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-size: $-calendar-info-fs;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(month-bottom) {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-size: $-calendar-info-fs;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<wd-toast selector="wd-year" />
|
||||||
|
|
||||||
|
<view class="wd-year year">
|
||||||
|
<view class="wd-year__title">{{ yearTitle(date) }}</view>
|
||||||
|
<view class="wd-year__months">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in months"
|
||||||
|
:key="index"
|
||||||
|
:class="`wd-year__month ${item.disabled ? 'is-disabled' : ''} ${item.type ? itemClass(item.type, value, type) : ''}`"
|
||||||
|
@click="handleDateClick(index)"
|
||||||
|
>
|
||||||
|
<view class="wd-year__month-top">{{ item.topInfo }}</view>
|
||||||
|
<view class="wd-year__month-text">{{ item.text }}月</view>
|
||||||
|
<view class="wd-year__month-bottom">{{ item.bottomInfo }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from 'vue'
|
||||||
|
import { deepClone, getType } from '../../common/util'
|
||||||
|
import { compareMonth, formatYearTitle, getDateByDefaultTime, getItemClass, getMonthByOffset, getMonthOffset } from '../utils'
|
||||||
|
import { useToast } from '../../wd-toast'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type: string
|
||||||
|
date: number
|
||||||
|
value: null | number | Array<number>
|
||||||
|
minDate: number
|
||||||
|
maxDate: number
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
formatter?: Function
|
||||||
|
maxRange?: number
|
||||||
|
rangePrompt?: string
|
||||||
|
allowSameDay?: boolean
|
||||||
|
defaultTime: Array<number>
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
allowSameDay: false
|
||||||
|
})
|
||||||
|
const toast = useToast('wd-year')
|
||||||
|
|
||||||
|
const months = ref<Record<string, any>[]>([])
|
||||||
|
|
||||||
|
const itemClass = computed(() => {
|
||||||
|
return (monthType, value, type) => {
|
||||||
|
return getItemClass(monthType, value, type)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const yearTitle = computed(() => {
|
||||||
|
return (date) => {
|
||||||
|
return formatYearTitle(date)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[() => props.type, () => props.date, () => props.value, () => props.minDate, () => props.maxDate, () => props.formatter],
|
||||||
|
() => {
|
||||||
|
setMonths()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function setMonths() {
|
||||||
|
const monthList: Record<string, any>[] = []
|
||||||
|
const date = new Date(props.date)
|
||||||
|
const year = date.getFullYear()
|
||||||
|
|
||||||
|
const value = props.value
|
||||||
|
const valueType = getType(value)
|
||||||
|
|
||||||
|
if (props.type.indexOf('range') > -1 && value && valueType !== 'array') {
|
||||||
|
console.error('[wot-design] value should be array when type is range')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let month = 0; month < 12; month++) {
|
||||||
|
const date = new Date(year, month, 1).getTime()
|
||||||
|
let type = getMonthType(date)
|
||||||
|
if (!type && compareMonth(date, Date.now()) === 0) {
|
||||||
|
type = 'current'
|
||||||
|
}
|
||||||
|
const monthObj = getFormatterDate(date, month, type)
|
||||||
|
monthList.push(monthObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
months.value = deepClone(monthList)
|
||||||
|
}
|
||||||
|
function getMonthType(date) {
|
||||||
|
if (props.type === 'monthrange' && typeof props.value === 'object') {
|
||||||
|
const [startDate, endDate] = props.value || []
|
||||||
|
|
||||||
|
if (startDate && compareMonth(date, startDate) === 0) {
|
||||||
|
if (endDate && compareMonth(startDate, endDate) === 0) {
|
||||||
|
return 'same'
|
||||||
|
}
|
||||||
|
return 'start'
|
||||||
|
} else if (endDate && compareMonth(date, endDate) === 0) {
|
||||||
|
return 'end'
|
||||||
|
} else if (startDate && endDate && compareMonth(date, startDate) === 1 && compareMonth(date, endDate) === -1) {
|
||||||
|
return 'middle'
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (props.value && compareMonth(date, props.value) === 0) {
|
||||||
|
return 'selected'
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleDateClick(index) {
|
||||||
|
const date = months.value[index]
|
||||||
|
|
||||||
|
if (date.disabled) return
|
||||||
|
|
||||||
|
switch (props.type) {
|
||||||
|
case 'month':
|
||||||
|
handleMonthChange(date)
|
||||||
|
break
|
||||||
|
case 'monthrange':
|
||||||
|
handleMonthRangeChange(date)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
handleMonthChange(date)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getDate(date) {
|
||||||
|
return props.defaultTime && props.defaultTime.length > 0 ? getDateByDefaultTime(date, props.defaultTime[0]) : date
|
||||||
|
}
|
||||||
|
function handleMonthChange(date) {
|
||||||
|
if (date.type !== 'selected') {
|
||||||
|
emit('change', {
|
||||||
|
value: getDate(date.date)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function handleMonthRangeChange(date) {
|
||||||
|
let value
|
||||||
|
const [startDate, endDate] = typeof props.value === 'object' ? props.value || [] : []
|
||||||
|
const compare = compareMonth(date.date, startDate)
|
||||||
|
|
||||||
|
// 禁止选择同个日期
|
||||||
|
if (!props.allowSameDay && !endDate && compare === 0) return
|
||||||
|
|
||||||
|
if (startDate && !endDate && compare > -1) {
|
||||||
|
if (props.maxRange && getMonthOffset(date.date, startDate) > props.maxRange) {
|
||||||
|
const maxEndDate = getMonthByOffset(startDate, props.maxRange - 1)
|
||||||
|
value = [startDate, getDate(maxEndDate)]
|
||||||
|
toast.show({
|
||||||
|
msg: props.rangePrompt || `选择月份不能超过${props.maxRange}个月`
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
value = [startDate, getDate(date.date)]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = [getDate(date.date), null]
|
||||||
|
}
|
||||||
|
emit('change', {
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function getFormatterDate(date, month, type) {
|
||||||
|
let monthObj = {
|
||||||
|
date: date,
|
||||||
|
text: month + 1,
|
||||||
|
topInfo: '',
|
||||||
|
bottomInfo: '',
|
||||||
|
type,
|
||||||
|
disabled: compareMonth(date, props.minDate) === -1 || compareMonth(date, props.maxDate) === 1
|
||||||
|
}
|
||||||
|
if (props.formatter) {
|
||||||
|
if (getType(props.formatter) === 'function') {
|
||||||
|
monthObj = props.formatter(monthObj)
|
||||||
|
} else {
|
||||||
|
console.error('[wot-design] error(wd-calendar-view): the formatter prop of wd-calendar-view should be a function')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return monthObj
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
@import '../../common/abstracts/variable';
|
||||||
|
@import '../../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(year-panel) {
|
||||||
|
@include e(title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
box-shadow: 0px 4px 8px 0 rgba(255, 255,255, 0.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(year-panel) {
|
||||||
|
font-size: $-calendar-fs;
|
||||||
|
padding: $-calendar-panel-padding;
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
padding: 5px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $-calendar-panel-title-fs;
|
||||||
|
color: $-calendar-panel-title-color;
|
||||||
|
box-shadow: 0px 4px 8px 0 rgba(0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 月份信息
|
||||||
|
*/
|
||||||
|
export interface YearInfo {
|
||||||
|
date: number
|
||||||
|
height: number
|
||||||
|
}
|
||||||
@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<view class="wd-year-panel">
|
||||||
|
<view v-if="showPanelTitle" class="wd-year-panel__title">{{ title }}</view>
|
||||||
|
<scroll-view class="wd-year-panel__container" :style="`height: ${scrollHeight}px`" scroll-y @scroll="yearScroll" :scroll-top="scrollTop">
|
||||||
|
<view v-for="(item, index) in years(minDate, maxDate)" :key="index" :id="`year${index}`">
|
||||||
|
<year
|
||||||
|
:type="type"
|
||||||
|
:date="item.date"
|
||||||
|
:value="value"
|
||||||
|
:min-date="minDate"
|
||||||
|
:max-date="maxDate"
|
||||||
|
:max-range="maxRange"
|
||||||
|
:formatter="formatter"
|
||||||
|
:range-prompt="rangePrompt"
|
||||||
|
:allow-same-day="allowSameDay"
|
||||||
|
:default-time="defaultTime"
|
||||||
|
@change="handleDateChange"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, ref, nextTick } from 'vue'
|
||||||
|
import { compareYear, formatYearTitle, getYears } from '../utils'
|
||||||
|
import { getType } from '../../common/util'
|
||||||
|
import Year from '../year/year.vue'
|
||||||
|
import type { YearInfo } from './type'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
type: string
|
||||||
|
value: Array<number> | number | null
|
||||||
|
minDate: number
|
||||||
|
maxDate: number
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
formatter?: Function
|
||||||
|
maxRange?: number
|
||||||
|
rangePrompt?: string
|
||||||
|
allowSameDay?: boolean
|
||||||
|
showPanelTitle?: boolean
|
||||||
|
defaultTime: Array<number>
|
||||||
|
panelHeight: number
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
allowSameDay: false,
|
||||||
|
showPanelTitle: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const title = ref<string>('')
|
||||||
|
const scrollTop = ref<number>(0) // 滚动位置
|
||||||
|
|
||||||
|
// 滚动区域的高度
|
||||||
|
const scrollHeight = computed(() => {
|
||||||
|
const scrollHeight: number = (props.panelHeight || 378) + (props.showPanelTitle ? 26 : 16)
|
||||||
|
return scrollHeight
|
||||||
|
})
|
||||||
|
|
||||||
|
const years = computed(() => {
|
||||||
|
return (minDate: number, maxDate: number): YearInfo[] => {
|
||||||
|
let years = getYears(minDate, maxDate).map((year) => {
|
||||||
|
return {
|
||||||
|
date: year,
|
||||||
|
height: 237
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return years
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
scrollIntoView()
|
||||||
|
})
|
||||||
|
|
||||||
|
const requestAnimationFrame = (cb = () => void 0) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni
|
||||||
|
.createSelectorQuery()
|
||||||
|
.selectViewport()
|
||||||
|
.boundingClientRect()
|
||||||
|
.exec(() => {
|
||||||
|
resolve(true)
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollIntoView() {
|
||||||
|
requestAnimationFrame().then(() => {
|
||||||
|
let activeDate
|
||||||
|
const type = getType(props.value)
|
||||||
|
if (type === 'array') {
|
||||||
|
activeDate = props.value![0]
|
||||||
|
} else if (type === 'number') {
|
||||||
|
activeDate = props.value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activeDate) {
|
||||||
|
activeDate = Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
const yearsInfo = years.value(props.minDate, props.maxDate)
|
||||||
|
|
||||||
|
let top: number = 0
|
||||||
|
for (let index = 0; index < yearsInfo.length; index++) {
|
||||||
|
if (compareYear(yearsInfo[index].date, activeDate) === 0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
top += yearsInfo[index] ? Number(yearsInfo[index].height) : 0
|
||||||
|
}
|
||||||
|
scrollTop.value = 0
|
||||||
|
nextTick(() => {
|
||||||
|
scrollTop.value = top
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const yearScroll = (e: Event) => {
|
||||||
|
const yearsInfo = years.value(props.minDate, props.maxDate)
|
||||||
|
if (yearsInfo.length <= 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const scrollTop = Math.max(0, (e.target as Element).scrollTop)
|
||||||
|
doSetSubtitle(scrollTop, yearsInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置小标题
|
||||||
|
* scrollTop 滚动条位置
|
||||||
|
*/
|
||||||
|
function doSetSubtitle(scrollTop: number, yearsInfo: YearInfo[]) {
|
||||||
|
let height: number = 0 // 月份高度和
|
||||||
|
for (let index = 0; index < yearsInfo.length; index++) {
|
||||||
|
height = height + yearsInfo[index].height
|
||||||
|
if (scrollTop < height + 45) {
|
||||||
|
title.value = formatYearTitle(yearsInfo[index].date)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDateChange({ value }) {
|
||||||
|
emit('change', {
|
||||||
|
value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
scrollIntoView
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(calendar) {
|
||||||
|
@include e(cell) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-calendar__arrow),
|
||||||
|
:deep(.wd-calendar__close) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-calendar__cell {
|
||||||
|
@include halfPixelBorder('top', $-cell-padding, $-dark-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(range-label-item) {
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include when(placeholder) {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(range-sperator) {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(calendar) {
|
||||||
|
@include when(border) {
|
||||||
|
.wd-calendar__cell {
|
||||||
|
@include halfPixelBorder('top', $-cell-padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(cell) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: $-cell-wrapper-padding $-cell-padding;
|
||||||
|
align-items: flex-start;
|
||||||
|
background-color: $-color-white;
|
||||||
|
text-decoration: none;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
font-size: $-cell-title-fs;
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(cell) {
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-calendar__value {
|
||||||
|
color: $-input-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(align-right) {
|
||||||
|
.wd-calendar__value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(error) {
|
||||||
|
.wd-calendar__value {
|
||||||
|
color: $-input-error-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-calendar__arrow) {
|
||||||
|
color: $-input-error-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(large) {
|
||||||
|
font-size: $-cell-title-fs-large;
|
||||||
|
|
||||||
|
:deep(.wd-calendar__arrow) {
|
||||||
|
font-size: $-cell-icon-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(center) {
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
:deep(.wd-calendar__arrow) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(error-message){
|
||||||
|
color: $-form-item-error-message-color;
|
||||||
|
font-size: $-form-item-error-message-font-size;
|
||||||
|
line-height: $-form-item-error-message-line-height;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
position: relative;
|
||||||
|
width: $-input-cell-label-width;
|
||||||
|
margin-right: $-cell-padding;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
@include when(required) {
|
||||||
|
padding-left: 12px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 2px;
|
||||||
|
content: '*';
|
||||||
|
font-size: $-cell-required-size;
|
||||||
|
line-height: 1.1;
|
||||||
|
color: $-cell-required-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value-wraper) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value) {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: $-cell-value-color;
|
||||||
|
|
||||||
|
@include when(ellipsis) {
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(placeholder) {
|
||||||
|
color: $-input-placeholder-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(body) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(arrow) {
|
||||||
|
display: block;
|
||||||
|
font-size: $-cell-icon-size;
|
||||||
|
color: $-cell-arrow-color;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(header) {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
color: $-action-sheet-color;
|
||||||
|
height: $-action-sheet-title-height;
|
||||||
|
line-height: $-action-sheet-title-height;
|
||||||
|
text-align: center;
|
||||||
|
font-size: $-action-sheet-title-fs;
|
||||||
|
font-weight: $-action-sheet-weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(close) {
|
||||||
|
position: absolute;
|
||||||
|
top: $-action-sheet-close-top;
|
||||||
|
right: $-action-sheet-close-right;
|
||||||
|
color: $-action-sheet-close-color;
|
||||||
|
font-size: $-action-sheet-close-fs;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(tabs) {
|
||||||
|
width: 222px;
|
||||||
|
margin: 10px auto 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(shortcuts) {
|
||||||
|
padding: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(tag) {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(view) {
|
||||||
|
@include when(show-confirm) {
|
||||||
|
height: 394px;
|
||||||
|
|
||||||
|
@include when(range) {
|
||||||
|
height: 384px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(range-label) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
@include when(monthrange) {
|
||||||
|
padding-bottom: 10px;
|
||||||
|
box-shadow: 0px 4px 8px 0 rgba(0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(range-label-item) {
|
||||||
|
flex: 1;
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
|
||||||
|
@include when(placeholder) {
|
||||||
|
color: rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(range-sperator) {
|
||||||
|
margin: 0 24px;
|
||||||
|
color: rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(confirm) {
|
||||||
|
padding: 12px 25px 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
@import "../common/abstracts/variable.scss";
|
||||||
|
@import "../common/abstracts/_mixin.scss";
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(card) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
|
||||||
|
@include when(rectangle) {
|
||||||
|
|
||||||
|
.wd-card__content {
|
||||||
|
@include halfPixelBorder('top', 0, $-dark-border-color);
|
||||||
|
}
|
||||||
|
.wd-card__footer {
|
||||||
|
@include halfPixelBorder('top', 0, $-dark-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title-content) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
@include e(content) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(card) {
|
||||||
|
padding: $-card-padding;
|
||||||
|
background-color: $-card-bg;
|
||||||
|
line-height: $-card-line-height;
|
||||||
|
margin: $-card-margin;
|
||||||
|
border-radius: $-card-radius;
|
||||||
|
box-shadow: $-card-shadow-color;
|
||||||
|
font-size: $-card-fs;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
@include when(rectangle) {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
.wd-card__title-content {
|
||||||
|
font-size: $-card-fs;
|
||||||
|
}
|
||||||
|
.wd-card__content {
|
||||||
|
position: relative;
|
||||||
|
padding: $-card-rectangle-content-padding;
|
||||||
|
|
||||||
|
@include halfPixelBorder('top', 0, $-card-content-border-color);
|
||||||
|
}
|
||||||
|
.wd-card__footer {
|
||||||
|
position: relative;
|
||||||
|
padding: $-card-rectangle-footer-padding;
|
||||||
|
|
||||||
|
@include halfPixelBorder('top', 0, $-card-content-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(title-content) {
|
||||||
|
padding: 16px 0;
|
||||||
|
color: $-card-title-color;
|
||||||
|
font-size: $-card-title-fs;
|
||||||
|
}
|
||||||
|
@include e(content) {
|
||||||
|
color: $-card-content-color;
|
||||||
|
line-height: $-card-content-line-height;
|
||||||
|
}
|
||||||
|
@include e(footer) {
|
||||||
|
padding: $-card-footer-padding;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<view :class="['wd-card', type == 'rectangle' ? 'is-rectangle' : '', customClass]">
|
||||||
|
<view :class="['wd-card__title-content', customTitleClass]">
|
||||||
|
<view class="wd-card__title">
|
||||||
|
<text v-if="title">{{ title }}</text>
|
||||||
|
<slot v-else name="title"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view :class="`wd-card__content ${customContentClass}`">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
<view :class="`wd-card__footer ${customFooterClass}`">
|
||||||
|
<slot name="footer"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-card',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
interface Props {
|
||||||
|
title?: string
|
||||||
|
type?: string
|
||||||
|
customClass?: string
|
||||||
|
customTitleClass?: string
|
||||||
|
customContentClass?: string
|
||||||
|
customFooterClass?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
type: '',
|
||||||
|
customClass: '',
|
||||||
|
customTitleClass: '',
|
||||||
|
customContentClass: '',
|
||||||
|
customFooterClass: ''
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
@import '../common/abstracts/variable.scss';
|
||||||
|
@import '../common/abstracts/_mixin.scss';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(cell-group) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-cell-group__title {
|
||||||
|
@include halfPixelBorder('bottom', 0, $-dark-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
background: $-dark-background2;
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(right) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(body) {
|
||||||
|
background: $-dark-background2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(cell-group) {
|
||||||
|
background-color: $-color-white;
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-cell-group__title {
|
||||||
|
@include halfPixelBorder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(title) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: $-cell-group-padding;
|
||||||
|
background: $-color-white;
|
||||||
|
font-size: $-cell-group-title-fs;
|
||||||
|
color: $-cell-group-title-color;
|
||||||
|
font-weight: $-fw-medium;
|
||||||
|
line-height: 1.43;
|
||||||
|
}
|
||||||
|
@include e(right) {
|
||||||
|
color: $-cell-group-value-color;
|
||||||
|
font-size: $-cell-group-value-fs;
|
||||||
|
}
|
||||||
|
@include e(body) {
|
||||||
|
background: $-color-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<view :class="['wd-cell-group', border ? 'is-border' : '', customClass]">
|
||||||
|
<view v-if="title || value || useSlot" class="wd-cell-group__title">
|
||||||
|
<!--左侧标题-->
|
||||||
|
<view class="wd-cell-group__left">
|
||||||
|
<text v-if="title">{{ title }}</text>
|
||||||
|
<slot v-else name="title"></slot>
|
||||||
|
</view>
|
||||||
|
<!--右侧标题-->
|
||||||
|
<view class="wd-cell-group__right">
|
||||||
|
<text v-if="value">{{ value }}</text>
|
||||||
|
<slot v-else name="value"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="wd-cell-group__body">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-cell-group',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { getCurrentInstance, provide, ref } from 'vue'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
customClass?: string
|
||||||
|
title?: string
|
||||||
|
value?: string
|
||||||
|
useSlot?: boolean
|
||||||
|
border?: boolean
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
useSlot: false,
|
||||||
|
border: false,
|
||||||
|
customClass: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const cellList = ref<any>([]) // cell列表
|
||||||
|
provide('cell-list', cellList)
|
||||||
|
const { proxy } = getCurrentInstance() as any
|
||||||
|
provide('cell-group', proxy)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,188 @@
|
|||||||
|
@import '../common/abstracts/variable.scss';
|
||||||
|
@import '../common/abstracts/_mixin.scss';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(cell) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include e(value) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(hover) {
|
||||||
|
background-color: $-dark-background4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-cell__wrapper {
|
||||||
|
@include halfPixelBorder('top', 0, $-dark-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-cell__arrow-right) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(cell) {
|
||||||
|
position: relative;
|
||||||
|
padding-left: $-cell-padding;
|
||||||
|
background-color: $-color-white;
|
||||||
|
text-decoration: none;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-cell__wrapper {
|
||||||
|
@include halfPixelBorder('top');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(wrapper) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: $-cell-wrapper-padding $-cell-padding $-cell-wrapper-padding 0;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
@include when(vertical) {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
.wd-cell__right {
|
||||||
|
margin-top: $-cell-vertical-top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-cell__value {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-cell__left {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(label) {
|
||||||
|
padding: $-cell-wrapper-padding-with-label $-cell-padding $-cell-wrapper-padding-with-label 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(left) {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
font-size: $-cell-title-fs;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin-right: $-cell-padding;
|
||||||
|
|
||||||
|
@include when(required) {
|
||||||
|
padding-left: 12px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '*';
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
font-size: $-cell-required-size;
|
||||||
|
color: $-cell-required-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(right) {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
font-size: $-cell-title-fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: $-cell-label-fs;
|
||||||
|
color: $-cell-label-color;
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(icon) {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
margin-right: $-cell-icon-right;
|
||||||
|
font-size: $-cell-icon-size;
|
||||||
|
height: $-cell-line-height;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(body){
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value) {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
font-size: $-cell-value-fs;
|
||||||
|
color: $-cell-value-color;
|
||||||
|
text-align: right;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(arrow-right) {
|
||||||
|
display: block;
|
||||||
|
margin-left: 8px;
|
||||||
|
width: $-cell-arrow-size;
|
||||||
|
font-size: $-cell-arrow-size;
|
||||||
|
color: $-cell-arrow-color;
|
||||||
|
height: $-cell-line-height;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(error-message){
|
||||||
|
color: $-form-item-error-message-color;
|
||||||
|
font-size: $-form-item-error-message-font-size;
|
||||||
|
line-height: $-form-item-error-message-line-height;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(link) {
|
||||||
|
-webkit-tap-highlight-color: $-cell-tap-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(hover) {
|
||||||
|
background-color: $-cell-tap-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(large) {
|
||||||
|
.wd-cell__title {
|
||||||
|
font-size: $-cell-title-fs-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-cell__wrapper {
|
||||||
|
padding-top: $-cell-wrapper-padding-large;
|
||||||
|
padding-bottom: $-cell-wrapper-padding-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-cell__label {
|
||||||
|
font-size: $-cell-label-fs-large;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-cell__icon) {
|
||||||
|
font-size: $-cell-icon-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(center) {
|
||||||
|
.wd-cell__wrapper {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,157 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
:class="['wd-cell', isBorder ? 'is-border' : '', size ? 'is-' + size : '', center ? 'is-center' : '', customClass]"
|
||||||
|
:hover-class="isLink || clickable ? 'is-hover' : 'none'"
|
||||||
|
hover-stay-time="70"
|
||||||
|
@click="onClick"
|
||||||
|
>
|
||||||
|
<view :class="['wd-cell__wrapper', vertical ? 'is-vertical' : '']">
|
||||||
|
<view
|
||||||
|
:class="['wd-cell__left', isRequired ? 'is-required' : '']"
|
||||||
|
:style="titleWidth ? 'min-width:' + titleWidth + ';max-width:' + titleWidth + ';' : ''"
|
||||||
|
>
|
||||||
|
<!--左侧icon部位-->
|
||||||
|
<wd-icon v-if="icon" :name="icon" :custom-class="`wd-cell__icon ${customIconClass}`"></wd-icon>
|
||||||
|
<slot v-else name="icon" />
|
||||||
|
|
||||||
|
<view class="wd-cell__title">
|
||||||
|
<!--title BEGIN-->
|
||||||
|
<view v-if="title" :class="customTitleClass">{{ title }}</view>
|
||||||
|
<slot v-else name="title"></slot>
|
||||||
|
<!--title END-->
|
||||||
|
|
||||||
|
<!--label BEGIN-->
|
||||||
|
<view v-if="label" :class="`wd-cell__label ${customLabelClass}`">{{ label }}</view>
|
||||||
|
<slot v-else name="label" />
|
||||||
|
<!--label END-->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!--right content BEGIN-->
|
||||||
|
<view class="wd-cell__right">
|
||||||
|
<view class="wd-cell__body">
|
||||||
|
<!--文案内容-->
|
||||||
|
<view :class="`wd-cell__value ${customValueClass}`">
|
||||||
|
<template v-if="value">{{ value }}</template>
|
||||||
|
<slot v-else></slot>
|
||||||
|
</view>
|
||||||
|
<!--箭头-->
|
||||||
|
<wd-icon v-if="isLink" custom-class="wd-cell__arrow-right" name="arrow-right" />
|
||||||
|
<slot v-else name="right-icon" />
|
||||||
|
</view>
|
||||||
|
<view v-if="errorMessage" class="wd-cell__error-message">{{ errorMessage }}</view>
|
||||||
|
</view>
|
||||||
|
<!--right content END-->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-cell',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useCell } from '../composables/useCell'
|
||||||
|
import { useParent } from '../composables/useParent'
|
||||||
|
import { FORM_KEY, FormItemRule } from '../wd-form/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title?: string
|
||||||
|
value?: string
|
||||||
|
icon?: string
|
||||||
|
label?: string
|
||||||
|
isLink?: boolean
|
||||||
|
to?: string
|
||||||
|
replace?: boolean
|
||||||
|
clickable?: boolean
|
||||||
|
size?: string
|
||||||
|
border?: boolean
|
||||||
|
titleWidth?: string
|
||||||
|
center?: boolean
|
||||||
|
required?: boolean
|
||||||
|
vertical?: boolean
|
||||||
|
prop?: string
|
||||||
|
rules?: FormItemRule[]
|
||||||
|
customClass?: string
|
||||||
|
customIconClass?: string
|
||||||
|
customLabelClass?: string
|
||||||
|
customValueClass?: string
|
||||||
|
customTitleClass?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
customClass: '',
|
||||||
|
customIconClass: '',
|
||||||
|
customLabelClass: '',
|
||||||
|
customValueClass: '',
|
||||||
|
customTitleClass: '',
|
||||||
|
isLink: false,
|
||||||
|
clickable: false,
|
||||||
|
replace: false,
|
||||||
|
center: false,
|
||||||
|
required: false,
|
||||||
|
vertical: false,
|
||||||
|
rules: () => []
|
||||||
|
})
|
||||||
|
|
||||||
|
const cell = useCell()
|
||||||
|
|
||||||
|
const isBorder = computed(() => {
|
||||||
|
return cell.border.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const { parent: form } = useParent(FORM_KEY)
|
||||||
|
|
||||||
|
const errorMessage = computed(() => {
|
||||||
|
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
|
||||||
|
return form.errorMessages[props.prop]
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 是否展示必填
|
||||||
|
const isRequired = computed(() => {
|
||||||
|
let formRequired = false
|
||||||
|
if (form && form.rules) {
|
||||||
|
const rules = form.rules
|
||||||
|
for (const key in rules) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(rules, key) && key === props.prop && Array.isArray(rules[key])) {
|
||||||
|
formRequired = rules[key].some((rule: FormItemRule) => rule.required)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props.required || props.rules.some((rule) => rule.required) || formRequired
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['click'])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 点击cell的handle
|
||||||
|
*/
|
||||||
|
function onClick() {
|
||||||
|
const url = props.to
|
||||||
|
|
||||||
|
if (props.clickable || props.isLink) {
|
||||||
|
emit('click')
|
||||||
|
}
|
||||||
|
if (url && props.isLink) {
|
||||||
|
if (props.replace) {
|
||||||
|
uni.redirectTo({ url })
|
||||||
|
} else {
|
||||||
|
uni.navigateTo({ url })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
@import "./../common/abstracts/_mixin.scss";
|
||||||
|
@import "./../common/abstracts/variable.scss";
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(checkbox-group) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include b(checkbox-group) {
|
||||||
|
background-color: $-checkbox-bg;
|
||||||
|
|
||||||
|
// 上下20px 左右15px 内部间隔12px
|
||||||
|
@include when(button) {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 3px 20px 15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,292 @@
|
|||||||
|
@import "./../common/abstracts/_mixin.scss";
|
||||||
|
@import "./../common/abstracts/variable.scss";
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(checkbox) {
|
||||||
|
@include e(shape) {
|
||||||
|
background: transparent;
|
||||||
|
border-color: $-checkbox-border-color;
|
||||||
|
color: $-checkbox-check-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
border-color: $-dark-color-gray;
|
||||||
|
background: $-dark-background4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-checkbox__check) {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(button) {
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
border-color: #c8c9cc;
|
||||||
|
background: #3a3a3c;
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__label {
|
||||||
|
border-color: #c8c9cc;
|
||||||
|
background: #3a3a3c;
|
||||||
|
color: #c8c9cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(button) {
|
||||||
|
.wd-checkbox__label {
|
||||||
|
background-color: $-dark-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__label {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(checkbox) {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: $-checkbox-margin;
|
||||||
|
font-size: 0;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
line-height: 1.2;
|
||||||
|
|
||||||
|
@include when(last-child) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(shape) {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: $-checkbox-size;
|
||||||
|
height: $-checkbox-size;
|
||||||
|
border: 2px solid $-checkbox-border-color;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: $-checkbox-check-color;
|
||||||
|
background: $-checkbox-bg;
|
||||||
|
vertical-align: middle;
|
||||||
|
transition: background 0.2s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
@include when(square) {
|
||||||
|
border-radius: $-checkbox-square-radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(input) {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(btn-check) {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: $-checkbox-icon-size;
|
||||||
|
margin-right: 4px;
|
||||||
|
height: $-checkbox-icon-size;
|
||||||
|
width: $-checkbox-icon-size;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(txt) {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 20px;
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: $-checkbox-label-margin;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: $-checkbox-label-fs;
|
||||||
|
color: $-checkbox-label-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(check) {
|
||||||
|
color: $-checkbox-check-color;
|
||||||
|
font-size: $-checkbox-icon-size;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
color: $-checkbox-checked-color;
|
||||||
|
background: currentColor;
|
||||||
|
border-color: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-checkbox__check) {
|
||||||
|
opacity: 1;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: -1px;
|
||||||
|
transform: translateX(-4.5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(button) {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: $-checkbox-margin;
|
||||||
|
vertical-align: top;
|
||||||
|
font-size: $-checkbox-button-font-size;
|
||||||
|
|
||||||
|
@include when(last-child) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-width: $-checkbox-button-min-width;
|
||||||
|
height: $-checkbox-button-height;
|
||||||
|
font-size: $-checkbox-button-font-size;
|
||||||
|
margin-left: 0;
|
||||||
|
padding: 5px 15px;
|
||||||
|
border: 1px solid $-checkbox-button-border;
|
||||||
|
background-color: $-checkbox-button-bg;
|
||||||
|
border-radius: $-checkbox-button-radius;
|
||||||
|
transition: color 0.2s, border 0.2s;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__label {
|
||||||
|
color: $-checkbox-checked-color;
|
||||||
|
background-color: $-checkbox-bg;
|
||||||
|
border-color: $-checkbox-checked-color;
|
||||||
|
border-color: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(inline) {
|
||||||
|
display: inline-block;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: $-checkbox-margin;
|
||||||
|
|
||||||
|
@include when(last-child) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
border-color: $-checkbox-border-color;
|
||||||
|
background: $-checkbox-disabled-check-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
color: $-checkbox-disabled-label-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
color: $-checkbox-disabled-check-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
color: $-checkbox-disabled-label-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(button) {
|
||||||
|
.wd-checkbox__label {
|
||||||
|
background: $-checkbox-disabled-color;
|
||||||
|
border-color: $-checkbox-button-border;
|
||||||
|
color: $-checkbox-disabled-label-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(checked) {
|
||||||
|
.wd-checkbox__label {
|
||||||
|
border-color: $-checkbox-button-disabled-border;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以下内容用于解决父子组件样式隔离的问题 —— START
|
||||||
|
@include when(cell-box) {
|
||||||
|
padding: 13px 15px;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
@include when(large) {
|
||||||
|
padding: 14px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(button-box) {
|
||||||
|
display: inline-flex;
|
||||||
|
width: 33.3333%;
|
||||||
|
padding: 12px 12px 0 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child::after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(large) {
|
||||||
|
.wd-checkbox__shape {
|
||||||
|
width: $-checkbox-large-size;
|
||||||
|
height: $-checkbox-large-size;
|
||||||
|
font-size: $-checkbox-large-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wd-checkbox__label {
|
||||||
|
font-size: $-checkbox-large-label-fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-checkbox__check) {
|
||||||
|
top: 0;
|
||||||
|
left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
@import "../common/abstracts/variable.scss";
|
||||||
|
@import "../common/abstracts/_mixin.scss";
|
||||||
|
|
||||||
|
@include b(circle) {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@include e(text) {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: $-circle-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,228 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(col-picker) {
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-col-picker__cell {
|
||||||
|
@include halfPixelBorder('top', $-cell-padding, $-dark-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(cell) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-col-picker__value {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value) {
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include m(placeholder) {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-col-picker__arrow) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(list) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(selected) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(col-picker) {
|
||||||
|
@include when(border) {
|
||||||
|
.wd-col-picker__cell {
|
||||||
|
@include halfPixelBorder('top', $-cell-padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(cell) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: $-cell-wrapper-padding $-cell-padding;
|
||||||
|
align-items: flex-start;
|
||||||
|
background-color: $-color-white;
|
||||||
|
text-decoration: none;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
font-size: $-cell-title-fs;
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
@include e(cell) {
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-col-picker__value {
|
||||||
|
color: $-input-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(align-right) {
|
||||||
|
.wd-col-picker__value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(error) {
|
||||||
|
.wd-col-picker__value {
|
||||||
|
color: $-input-error-color;
|
||||||
|
}
|
||||||
|
:deep(.wd-col-picker__arrow) {
|
||||||
|
color: $-input-error-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(large) {
|
||||||
|
font-size: $-cell-title-fs-large;
|
||||||
|
|
||||||
|
:deep(.wd-col-picker__arrow) {
|
||||||
|
font-size: $-cell-icon-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(error-message){
|
||||||
|
color: $-form-item-error-message-color;
|
||||||
|
font-size: $-form-item-error-message-font-size;
|
||||||
|
line-height: $-form-item-error-message-line-height;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
@include e(label) {
|
||||||
|
position: relative;
|
||||||
|
width: $-input-cell-label-width;
|
||||||
|
margin-right: $-cell-padding;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
@include when(required) {
|
||||||
|
padding-left: 12px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 2px;
|
||||||
|
content: '*';
|
||||||
|
font-size: $-cell-required-size;
|
||||||
|
line-height: 1.1;
|
||||||
|
color: $-cell-required-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(value-wraper) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
@include e(value) {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: $-cell-value-color;
|
||||||
|
|
||||||
|
@include when(ellipsis) {
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
@include m(placeholder) {
|
||||||
|
color: $-input-placeholder-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(body) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
@include edeep(arrow) {
|
||||||
|
display: block;
|
||||||
|
font-size: $-cell-icon-size;
|
||||||
|
color: $-cell-arrow-color;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
@include e(selected) {
|
||||||
|
height: $-col-picker-selected-height;
|
||||||
|
font-size: $-col-picker-selected-fs;
|
||||||
|
color: $-col-picker-selected-color;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
@include e(selected-container){
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
@include e(selected-item) {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
height: $-col-picker-selected-height;
|
||||||
|
line-height: $-col-picker-selected-height;
|
||||||
|
padding: $-col-picker-selected-padding;
|
||||||
|
|
||||||
|
@include when(selected) {
|
||||||
|
font-weight: $-col-picker-selected-fw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(selected-line) {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
width: $-col-picker-line-width;
|
||||||
|
left: 0;
|
||||||
|
height: $-col-picker-line-height;
|
||||||
|
background: $-col-picker-line-color;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: calc($-col-picker-line-height / 2);
|
||||||
|
box-shadow: $-col-picker-line-box-shadow;
|
||||||
|
}
|
||||||
|
@include e(list-container){
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
@include e(list) {
|
||||||
|
height: $-col-picker-list-height;
|
||||||
|
padding-bottom: $-col-picker-list-padding-bottom;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
color: $-col-picker-list-color;
|
||||||
|
font-size: $-col-picker-list-fs;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
@include e(list-item) {
|
||||||
|
display: flex;
|
||||||
|
padding: $-col-picker-list-item-padding;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
@include when(selected) {
|
||||||
|
color: $-col-picker-list-color-checked;
|
||||||
|
|
||||||
|
:deep(.wd-col-picker__checked) {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(disabled) {
|
||||||
|
color: $-col-picker-list-color-disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(list-item-label) {
|
||||||
|
line-height: 1.285;
|
||||||
|
}
|
||||||
|
@include e(list-item-tip) {
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: $-col-picker-list-fs-tip;
|
||||||
|
color: $-col-picker-list-color-tip;
|
||||||
|
}
|
||||||
|
@include edeep(checked) {
|
||||||
|
display: block;
|
||||||
|
margin-left: 4px;
|
||||||
|
font-size: $-col-picker-list-checked-icon-size;
|
||||||
|
color: $-col-picker-list-color-checked;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
@include e(loading) {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
$i: 1;
|
||||||
|
|
||||||
|
@include b(col) {
|
||||||
|
float: left;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@while $i <= 24 {
|
||||||
|
.wd-col__#{$i} {
|
||||||
|
width: calc(100% / 24 * $i);
|
||||||
|
}
|
||||||
|
.wd-col__offset-#{$i} {
|
||||||
|
margin-left: calc(100% / 24 * $i);
|
||||||
|
}
|
||||||
|
$i: $i + 1;
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-06-13 11:34:35
|
||||||
|
* @LastEditTime: 2023-11-20 13:32:00
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-col\wd-col.vue
|
||||||
|
* 记得注释
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view :class="['wd-col', span && 'wd-col__' + span, offset && 'wd-col__offset-' + offset, customClass]" :style="style">
|
||||||
|
<!-- 每一列 -->
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-col',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { inject, provide, watch } from 'vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
interface Props {
|
||||||
|
span?: number
|
||||||
|
offset?: number
|
||||||
|
customClass?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
span: 24,
|
||||||
|
offset: 0,
|
||||||
|
customClass: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const style = ref<string>('')
|
||||||
|
const row: any = inject('$row')
|
||||||
|
|
||||||
|
watch([() => props.span, () => props.offset], () => {
|
||||||
|
check()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => row.gutter,
|
||||||
|
(newVal) => {
|
||||||
|
setGutter(newVal || 0)
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
function check() {
|
||||||
|
const { span, offset } = props
|
||||||
|
if (span < 0 || offset < 0) {
|
||||||
|
console.error('[wot-design] warning(wd-col): attribute span/offset must be greater than or equal to 0')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGutter(gutter: number) {
|
||||||
|
const padding = `${gutter / 2}px`
|
||||||
|
const customStyle = gutter > 0 ? `padding-left: ${padding}; padding-right: ${padding};background-clip: content-box;` : ''
|
||||||
|
|
||||||
|
if (customStyle !== style.value) {
|
||||||
|
style.value = customStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provide('setGutter', setGutter) // 将设置子项方法导出
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(collapse-item) {
|
||||||
|
@include halfPixelBorder('top', 0, $-dark-border-color);
|
||||||
|
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(body) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-collapse-item__title {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
.wd-collapse-item__arrow {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include b(collapse-item) {
|
||||||
|
position: relative;
|
||||||
|
@include halfPixelBorder('top');
|
||||||
|
|
||||||
|
|
||||||
|
@include e(header) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: $-collapse-header-padding;
|
||||||
|
overflow: hidden;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title) {
|
||||||
|
color: $-collapse-title-color;
|
||||||
|
font-weight: $-fw-medium;
|
||||||
|
font-size: $-collapse-title-fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(arrow) {
|
||||||
|
display: block;
|
||||||
|
font-size: $-collapse-arrow-size;
|
||||||
|
color: $-collapse-arrow-color;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
|
||||||
|
@include when(retract) {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(wrapper) {
|
||||||
|
position: relative;
|
||||||
|
transition: height 0.3s ease-in-out;
|
||||||
|
overflow: hidden;
|
||||||
|
will-change: height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(body) {
|
||||||
|
color: $-collapse-body-color;
|
||||||
|
font-size: $-collapse-body-fs;
|
||||||
|
padding: $-collapse-body-padding;
|
||||||
|
line-height: 1.43;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-collapse-item__title {
|
||||||
|
color: $-collapse-disabled-color;
|
||||||
|
}
|
||||||
|
.wd-collapse-item__arrow {
|
||||||
|
color: $-collapse-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
@import "../common/abstracts/variable";
|
||||||
|
@import "../common/abstracts/mixin";
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(collapse) {
|
||||||
|
background: $-dark-background2;
|
||||||
|
|
||||||
|
@include e(content) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(collapse) {
|
||||||
|
background: $-color-white;
|
||||||
|
|
||||||
|
@include when(viewmore) {
|
||||||
|
padding: $-collapse-side-padding;
|
||||||
|
}
|
||||||
|
@include e(content) {
|
||||||
|
font-size: $-collapse-body-fs;
|
||||||
|
color: $-collapse-body-color;
|
||||||
|
|
||||||
|
@include when(retract) {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: $-collapse-retract-fs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(more) {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: $-collapse-retract-fs;
|
||||||
|
margin-top: 8px;
|
||||||
|
color: $-collapse-more-color;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
@include e(more-txt) {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
@include e(arrow) {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
font-size: $-collapse-arrow-size;
|
||||||
|
height: $-collapse-arrow-size;
|
||||||
|
line-height: $-collapse-arrow-size;
|
||||||
|
|
||||||
|
@include when(retract) {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* 折叠面板子项
|
||||||
|
*/
|
||||||
|
export interface CollapseItem {
|
||||||
|
name: string
|
||||||
|
expanded: boolean
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-06-13 11:34:35
|
||||||
|
* @LastEditTime: 2023-08-16 10:51:08
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-config-provider\wd-config-provider.vue
|
||||||
|
* 记得注释
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view :class="themeClass" :style="themeStyle">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-config-provider',
|
||||||
|
options: {
|
||||||
|
virtualHost: true,
|
||||||
|
addGlobalClass: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
type ConfigProviderTheme = 'light' | 'dark'
|
||||||
|
interface Props {
|
||||||
|
theme?: ConfigProviderTheme
|
||||||
|
themeVars?: Record<string, any>
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
theme: 'light',
|
||||||
|
themeVars: () => {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const themeClass = computed(() => {
|
||||||
|
return `wot-theme-${props.theme}`
|
||||||
|
})
|
||||||
|
|
||||||
|
const themeStyle = computed(() => {
|
||||||
|
return mapThemeVarsToCSSVars(props.themeVars)
|
||||||
|
})
|
||||||
|
|
||||||
|
const kebabCase = (str: string): string => {
|
||||||
|
str = str.replace(str.charAt(0), str.charAt(0).toLocaleLowerCase())
|
||||||
|
return str.replace(/([a-z])([A-Z])/g, (_, p1, p2) => p1 + '-' + p2.toLowerCase())
|
||||||
|
}
|
||||||
|
const colorRgb = (str: string) => {
|
||||||
|
if (!str) return
|
||||||
|
var sColor = str.toLowerCase()
|
||||||
|
//十六进制颜色值的正则表达式
|
||||||
|
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
|
||||||
|
// 如果是16进制颜色
|
||||||
|
if (sColor && reg.test(sColor)) {
|
||||||
|
if (sColor.length === 4) {
|
||||||
|
var sColorNew = '#'
|
||||||
|
for (let i = 1; i < 4; i += 1) {
|
||||||
|
sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
|
||||||
|
}
|
||||||
|
sColor = sColorNew
|
||||||
|
}
|
||||||
|
//处理六位的颜色值
|
||||||
|
var sColorChange: number[] = []
|
||||||
|
for (let i = 1; i < 7; i += 2) {
|
||||||
|
sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
|
||||||
|
}
|
||||||
|
return sColorChange.join(',')
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapThemeVarsToCSSVars = (themeVars: Record<string, string>) => {
|
||||||
|
if (!themeVars) return
|
||||||
|
const cssVars: Record<string, string> = {}
|
||||||
|
Object.keys(themeVars).forEach((key) => {
|
||||||
|
cssVars[`--wot-${kebabCase(key)}`] = themeVars[key]
|
||||||
|
})
|
||||||
|
|
||||||
|
return cssVars
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(count-down) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include b(count-down) {
|
||||||
|
color: $-count-down-text-color;
|
||||||
|
font-size: $-count-down-font-size;
|
||||||
|
line-height: $-count-down-line-height;
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
import { padZero } from '../common/util'
|
||||||
|
|
||||||
|
export type TimeData = {
|
||||||
|
days: number
|
||||||
|
hours: number
|
||||||
|
minutes: number
|
||||||
|
seconds: number
|
||||||
|
milliseconds: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseFormat(format: string, timeData: TimeData): string {
|
||||||
|
const { days } = timeData
|
||||||
|
let { hours, minutes, seconds, milliseconds } = timeData
|
||||||
|
|
||||||
|
if (format.includes('DD')) {
|
||||||
|
format = format.replace('DD', padZero(days))
|
||||||
|
} else {
|
||||||
|
hours += days * 24
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('HH')) {
|
||||||
|
format = format.replace('HH', padZero(hours))
|
||||||
|
} else {
|
||||||
|
minutes += hours * 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('mm')) {
|
||||||
|
format = format.replace('mm', padZero(minutes))
|
||||||
|
} else {
|
||||||
|
seconds += minutes * 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('ss')) {
|
||||||
|
format = format.replace('ss', padZero(seconds))
|
||||||
|
} else {
|
||||||
|
milliseconds += seconds * 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format.includes('S')) {
|
||||||
|
const ms = padZero(milliseconds, 3)
|
||||||
|
|
||||||
|
if (format.includes('SSS')) {
|
||||||
|
format = format.replace('SSS', ms)
|
||||||
|
} else if (format.includes('SS')) {
|
||||||
|
format = format.replace('SS', ms.slice(0, 2))
|
||||||
|
} else {
|
||||||
|
format = format.replace('S', ms.charAt(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return format
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSameSecond(time1: number, time2: number): boolean {
|
||||||
|
return Math.floor(time1 / 1000) === Math.floor(time2 / 1000)
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
@import "./../common/abstracts/_mixin.scss";
|
||||||
|
@import "./../common/abstracts/variable.scss";
|
||||||
|
|
||||||
|
:deep(.wd-curtain){
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: $-curtain-content-radius;
|
||||||
|
overflow-y: visible;
|
||||||
|
background: transparent;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
@include bdeep(curtain) {
|
||||||
|
|
||||||
|
@include e(content) {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: $-curtain-content-radius;
|
||||||
|
}
|
||||||
|
@include e(content-link) {
|
||||||
|
display: block;
|
||||||
|
border-radius: $-curtain-content-radius;
|
||||||
|
}
|
||||||
|
@include e(content-img) {
|
||||||
|
display: block;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
border-radius: $-curtain-content-radius;
|
||||||
|
}
|
||||||
|
@include edeep(content-close) {
|
||||||
|
position: absolute;
|
||||||
|
margin: 0;
|
||||||
|
padding: 6px;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
color: $-curtain-content-close-color;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
&.top {
|
||||||
|
margin: 0 0 0 -18px;
|
||||||
|
top: -62px;
|
||||||
|
right: unset;
|
||||||
|
left: 50%;
|
||||||
|
bottom: unset;
|
||||||
|
}
|
||||||
|
&.top-left {
|
||||||
|
margin: 0;
|
||||||
|
top: -62px;
|
||||||
|
right: unset;
|
||||||
|
left: -6px;
|
||||||
|
bottom: unset;
|
||||||
|
}
|
||||||
|
&.top-right {
|
||||||
|
margin: 0;
|
||||||
|
top: -62px;
|
||||||
|
right: -6px;
|
||||||
|
left: unset;
|
||||||
|
bottom: unset;
|
||||||
|
}
|
||||||
|
&.bottom {
|
||||||
|
margin: 0 0 0 -18px;
|
||||||
|
top: unset;
|
||||||
|
right: unset;
|
||||||
|
left: 50%;
|
||||||
|
bottom: -62px;
|
||||||
|
}
|
||||||
|
&.bottom-left {
|
||||||
|
margin: 0;
|
||||||
|
top: unset;
|
||||||
|
right: unset;
|
||||||
|
left: -6px;
|
||||||
|
bottom: -62px;
|
||||||
|
}
|
||||||
|
&.bottom-right {
|
||||||
|
margin: 0;
|
||||||
|
top: unset;
|
||||||
|
right: -6px;
|
||||||
|
left: unset;
|
||||||
|
bottom: -62px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<wd-popup
|
||||||
|
v-model="show"
|
||||||
|
transition="zoom-in"
|
||||||
|
position="center"
|
||||||
|
:close-on-click-modal="closeOnClickModal"
|
||||||
|
:hide-when-close="hideWhenClose"
|
||||||
|
@before-enter="beforeenter"
|
||||||
|
@enter="enter"
|
||||||
|
@after-enter="afterenter"
|
||||||
|
@before-leave="beforeleave"
|
||||||
|
@leave="leave"
|
||||||
|
@after-leave="afterleave"
|
||||||
|
@close="close"
|
||||||
|
@click-modal="clickModal"
|
||||||
|
:custom-class="`wd-curtain ${customClass}`"
|
||||||
|
>
|
||||||
|
<view class="wd-curtain__content">
|
||||||
|
<image :src="src" class="wd-curtain__content-img" :style="imgStyle" @click="clickImage" @error="imgErr" @load="imgLoad"></image>
|
||||||
|
<wd-icon name="close-outline" size="24px" :custom-class="`wd-curtain__content-close ${closePosition}`" @click="close" />
|
||||||
|
</view>
|
||||||
|
</wd-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-curtain',
|
||||||
|
options: {
|
||||||
|
virtualHost: true,
|
||||||
|
addGlobalClass: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
type ClosePosition = 'inset' | 'top' | 'bottom' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
||||||
|
interface Props {
|
||||||
|
customClass?: string
|
||||||
|
value: boolean
|
||||||
|
closePosition?: ClosePosition
|
||||||
|
src?: string
|
||||||
|
to?: string
|
||||||
|
width?: number
|
||||||
|
closeOnClickModal?: boolean
|
||||||
|
hideWhenClose?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
customClass: '',
|
||||||
|
value: false,
|
||||||
|
closePosition: 'inset',
|
||||||
|
closeOnClickModal: false,
|
||||||
|
hideWhenClose: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const show = ref<boolean>(false)
|
||||||
|
const imgSucc = ref<boolean>(true)
|
||||||
|
const imgStyle = ref<string>('')
|
||||||
|
const imgScale = ref<number>(1)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
() => {
|
||||||
|
computedShowImg()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.width,
|
||||||
|
() => {
|
||||||
|
computeImgStyle()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'beforeenter',
|
||||||
|
'enter',
|
||||||
|
'afterenter',
|
||||||
|
'beforeleave',
|
||||||
|
'leave',
|
||||||
|
'afterleave',
|
||||||
|
'close',
|
||||||
|
'closed',
|
||||||
|
'click-modal',
|
||||||
|
'load',
|
||||||
|
'error',
|
||||||
|
'click'
|
||||||
|
])
|
||||||
|
|
||||||
|
function computedShowImg() {
|
||||||
|
if (props.value && imgSucc.value) {
|
||||||
|
show.value = true
|
||||||
|
} else {
|
||||||
|
show.value = false
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeImgStyle() {
|
||||||
|
let style = ''
|
||||||
|
if (props.width) {
|
||||||
|
style += `width: ${props.width}px ;`
|
||||||
|
style += `height: ${props.width / imgScale.value}px`
|
||||||
|
}
|
||||||
|
imgStyle.value = style
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeenter() {
|
||||||
|
emit('beforeenter')
|
||||||
|
}
|
||||||
|
|
||||||
|
function enter() {
|
||||||
|
emit('enter')
|
||||||
|
}
|
||||||
|
function afterenter() {
|
||||||
|
emit('afterenter')
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeleave() {
|
||||||
|
emit('beforeleave')
|
||||||
|
}
|
||||||
|
|
||||||
|
function leave() {
|
||||||
|
emit('leave')
|
||||||
|
}
|
||||||
|
|
||||||
|
function afterleave() {
|
||||||
|
emit('afterleave')
|
||||||
|
emit('closed')
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
show.value = false
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickModal() {
|
||||||
|
emit('click-modal')
|
||||||
|
}
|
||||||
|
|
||||||
|
function imgLoad(event) {
|
||||||
|
const { height, width } = event.detail
|
||||||
|
imgScale.value = width / height
|
||||||
|
imgSucc.value = true
|
||||||
|
computeImgStyle()
|
||||||
|
emit('load')
|
||||||
|
}
|
||||||
|
function imgErr() {
|
||||||
|
imgSucc.value = false
|
||||||
|
emit('error')
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickImage() {
|
||||||
|
if (props.to) {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: props.to
|
||||||
|
})
|
||||||
|
}
|
||||||
|
emit('click')
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
@import "./../common/abstracts/_mixin.scss";
|
||||||
|
@import "./../common/abstracts/variable.scss";
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(picker) {
|
||||||
|
@include e(cell) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
@include e(value) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(placeholder) {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-picker__cell {
|
||||||
|
@include halfPixelBorder('top', $-cell-padding, $-dark-border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-picker__arrow){
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(action) {
|
||||||
|
@include m(cancel) {
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(region) {
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include when(active) {
|
||||||
|
background: $-picker-region-bg-active-color;
|
||||||
|
color: $-dark-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(picker) {
|
||||||
|
@include edeep(popup) {
|
||||||
|
border-radius: 16px 16px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(wraper) {
|
||||||
|
padding-bottom: var(--window-bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(border) {
|
||||||
|
.wd-picker__cell {
|
||||||
|
@include halfPixelBorder("top", $-cell-padding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(large) {
|
||||||
|
.wd-picker__cell {
|
||||||
|
font-size: $-cell-title-fs-large;
|
||||||
|
}
|
||||||
|
:deep(.wd-picker__arrow) {
|
||||||
|
font-size: $-cell-icon-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(error) {
|
||||||
|
.wd-picker__value,
|
||||||
|
.wd-picker__placeholder {
|
||||||
|
color: $-input-error-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.wd-picker__arrow){
|
||||||
|
color: $-input-error-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(align-right) {
|
||||||
|
.wd-picker__value {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(cell) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: $-cell-wrapper-padding $-cell-padding;
|
||||||
|
align-items: flex-start;
|
||||||
|
background-color: $-color-white;
|
||||||
|
text-decoration: none;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
font-size: $-cell-title-fs;
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-picker__value {
|
||||||
|
color: $-input-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(disabled) {
|
||||||
|
.wd-picker__value {
|
||||||
|
color: $-picker-column-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(error-message){
|
||||||
|
color: $-form-item-error-message-color;
|
||||||
|
font-size: $-form-item-error-message-font-size;
|
||||||
|
line-height: $-form-item-error-message-line-height;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(label) {
|
||||||
|
position: relative;
|
||||||
|
width: $-input-cell-label-width;
|
||||||
|
margin-right: $-cell-padding;
|
||||||
|
color: $-cell-title-color;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
@include when(required) {
|
||||||
|
padding-left: 12px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 2px;
|
||||||
|
content: "*";
|
||||||
|
font-size: $-cell-required-size;
|
||||||
|
line-height: 1.1;
|
||||||
|
color: $-cell-required-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value-wraper) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(value) {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 10px;
|
||||||
|
color: $-cell-value-color;
|
||||||
|
|
||||||
|
@include when(ellipsis) {
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(body) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(placeholder) {
|
||||||
|
color: $-input-placeholder-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(arrow) {
|
||||||
|
display: block;
|
||||||
|
font-size: $-cell-icon-size;
|
||||||
|
color: $-cell-arrow-color;
|
||||||
|
line-height: $-cell-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(toolbar) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
font-size: $-picker-toolbar-fs;
|
||||||
|
height: $-picker-toolbar-height;
|
||||||
|
line-height: $-picker-action-height;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(action) {
|
||||||
|
display: block;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: $-picker-toolbar-fs;
|
||||||
|
color: $-picker-toolbar-finish-color;
|
||||||
|
background: transparent;
|
||||||
|
padding: 24px 15px 14px 15px;
|
||||||
|
|
||||||
|
@include m(cancel) {
|
||||||
|
color: $-picker-toolbar-cancel-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include when(loading) {
|
||||||
|
color: $-picker-loading-button-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include e(title) {
|
||||||
|
display: block;
|
||||||
|
float: 1;
|
||||||
|
color: $-picker-toolbar-title-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(region-tabs) {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(region) {
|
||||||
|
width: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
color: $-picker-region-color;
|
||||||
|
text-align: center;
|
||||||
|
padding: 14px 0;
|
||||||
|
font-size: $-picker-region-fs;
|
||||||
|
line-height: 16px;
|
||||||
|
transition: all 0.15s ease-out;
|
||||||
|
|
||||||
|
@include when(active) {
|
||||||
|
background: $-picker-region-bg-active-color;
|
||||||
|
color: $-color-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(region-time) {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(hidden) {
|
||||||
|
visibility: hidden;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(show) {
|
||||||
|
visibility: visible;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(divider) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
|
||||||
|
@include e(line) {
|
||||||
|
background: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(divider) {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
padding: $-divider-padding;
|
||||||
|
align-items: center;
|
||||||
|
color: $-divider-color;
|
||||||
|
font-size: $-divider-fs;
|
||||||
|
|
||||||
|
@include e(line) {
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
background: $-divider-line-color;
|
||||||
|
}
|
||||||
|
@include e(content) {
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
<template>
|
||||||
|
<view :class="`wd-divider ${customClass}`">
|
||||||
|
<view class="wd-divider__line" :style="color ? 'background: ' + color : ''"></view>
|
||||||
|
<view class="wd-divider__content" :style="color ? 'color: ' + color : ''">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
<view class="wd-divider__line" :style="color ? 'background: ' + color : ''"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-divider',
|
||||||
|
options: {
|
||||||
|
virtualHost: true,
|
||||||
|
addGlobalClass: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
interface Props {
|
||||||
|
customClass?: string
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
color: '',
|
||||||
|
customClass: ''
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(drop-item) {
|
||||||
|
color: $-dark-color;
|
||||||
|
|
||||||
|
@include e(tip) {
|
||||||
|
color: $-dark-color3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(drop-item) {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: $-drop-menu-item-fs;
|
||||||
|
color: $-drop-menu-item-color;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 101;
|
||||||
|
|
||||||
|
.wd-drop-item__popup {
|
||||||
|
position: absolute;
|
||||||
|
max-height: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(option) {
|
||||||
|
display: flex;
|
||||||
|
height: $-drop-menu-item-height;
|
||||||
|
line-height: $-drop-menu-item-height;
|
||||||
|
padding: 0 $-drop-menu-side-padding;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transition: color .2s;
|
||||||
|
|
||||||
|
@include when(active) {
|
||||||
|
color: $-drop-menu-item-color-active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(title){
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(tip) {
|
||||||
|
display: inline-block;
|
||||||
|
color: $-drop-menu-item-color-tip;
|
||||||
|
font-size: $-drop-menu-item-fs-tip;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(icon){
|
||||||
|
display: block;
|
||||||
|
font-size: $-drop-menu-option-check-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(modal) {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,244 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="showWrapper" :class="`wd-drop-item ${customClass}`" :style="`z-index: ${zIndex}; ${positionStyle}`">
|
||||||
|
<wd-popup
|
||||||
|
v-model="showPop"
|
||||||
|
:z-index="zIndex"
|
||||||
|
:duration="duration"
|
||||||
|
:position="position"
|
||||||
|
custom-style="position: absolute; max-height: 80%;"
|
||||||
|
modal-style="position: absolute;"
|
||||||
|
:modal="modal"
|
||||||
|
:close-on-click-modal="closeOnClickModal"
|
||||||
|
@click-modal="close"
|
||||||
|
@before-enter="handleOpen"
|
||||||
|
@after-enter="handleOpened"
|
||||||
|
@before-leave="handleClose"
|
||||||
|
@after-leave="onPopupClose"
|
||||||
|
>
|
||||||
|
<view v-if="options.length">
|
||||||
|
<view
|
||||||
|
v-for="(item, index) in options"
|
||||||
|
:key="index"
|
||||||
|
@click="choose(index)"
|
||||||
|
:class="`wd-drop-item__option ${(item[valueKey] !== '' ? item[valueKey] : item) === modelValue ? 'is-active' : ''}`"
|
||||||
|
>
|
||||||
|
<view :class="`wd-drop-item__title ${customTitle}`">
|
||||||
|
<text>{{ item[labelKey] ? item[labelKey] : item }}</text>
|
||||||
|
<text v-if="item[tipKey]" class="wd-drop-item__tip">{{ item[tipKey] }}</text>
|
||||||
|
</view>
|
||||||
|
<wd-icon
|
||||||
|
v-if="(item[valueKey] !== '' ? item[valueKey] : item) === modelValue"
|
||||||
|
:name="iconName"
|
||||||
|
size="20px"
|
||||||
|
:class="`wd-drop-item__icon ${customIcon}`"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot v-else />
|
||||||
|
</wd-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-drop-menu-item',
|
||||||
|
options: {
|
||||||
|
virtualHost: true,
|
||||||
|
addGlobalClass: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, getCurrentInstance, inject, onBeforeMount, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||||
|
import { pushToQueue, removeFromQueue } from '../common/clickoutside'
|
||||||
|
import { type Queue, queueKey } from '../composables/useQueue'
|
||||||
|
import { debounce } from '../common/util'
|
||||||
|
import type { PopupType } from '../wd-popup/type'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
customClass?: string
|
||||||
|
customTitle?: string
|
||||||
|
customIcon?: string
|
||||||
|
// 当前选中的value
|
||||||
|
modelValue?: string | number
|
||||||
|
// 可能是 array || String
|
||||||
|
options?: Array<Record<string, any>>
|
||||||
|
useDropItemSlot?: boolean
|
||||||
|
disabled?: boolean
|
||||||
|
iconName?: string
|
||||||
|
title?: string
|
||||||
|
valueKey?: string
|
||||||
|
labelKey?: string
|
||||||
|
tipKey?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
customClass: '',
|
||||||
|
customTitle: '',
|
||||||
|
customIcon: '',
|
||||||
|
options: () => [],
|
||||||
|
useDropItemSlot: false,
|
||||||
|
disabled: false,
|
||||||
|
iconName: 'check',
|
||||||
|
valueKey: 'value',
|
||||||
|
labelKey: 'label',
|
||||||
|
tipKey: 'tip'
|
||||||
|
})
|
||||||
|
|
||||||
|
const queue = inject<Queue | null>(queueKey, null)
|
||||||
|
const showWrapper = ref<boolean>(false)
|
||||||
|
const showPop = ref<boolean>(false)
|
||||||
|
const position = ref<PopupType>()
|
||||||
|
const transName = ref<string>('')
|
||||||
|
const zIndex = ref<number>(12)
|
||||||
|
const displayTitle = ref<string>('')
|
||||||
|
const modal = ref<boolean>(true)
|
||||||
|
const closeOnClickModal = ref<boolean>(true)
|
||||||
|
const duration = ref<number>(0)
|
||||||
|
|
||||||
|
const parent = inject<any>('dropMenu')
|
||||||
|
const { proxy } = getCurrentInstance() as any
|
||||||
|
|
||||||
|
const updateTitle = debounce(function () {
|
||||||
|
setDisplayTitle()
|
||||||
|
parent && parent.$.exposed.updateTitle && parent.$.exposed.updateTitle()
|
||||||
|
}, 50)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(newValue) => {
|
||||||
|
if (typeof newValue !== 'number' && typeof newValue !== 'string') {
|
||||||
|
console.error('[wot-design] warning(wd-drop-menu-item): the type of value should be a number or a string.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
updateTitle()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[() => props.options, () => props.title],
|
||||||
|
() => {
|
||||||
|
updateTitle()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
if (queue && queue.pushToQueue) {
|
||||||
|
queue.pushToQueue(proxy)
|
||||||
|
} else {
|
||||||
|
pushToQueue(proxy)
|
||||||
|
}
|
||||||
|
if (parent) {
|
||||||
|
parent.$.exposed.setChild && parent.$.exposed.setChild(proxy)
|
||||||
|
updateTitle()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (queue && queue.removeFromQueue) {
|
||||||
|
queue.removeFromQueue(proxy)
|
||||||
|
} else {
|
||||||
|
removeFromQueue(proxy)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setDisplayTitle()
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['change', 'update:modelValue', 'open', 'opened', 'closed', 'close'])
|
||||||
|
|
||||||
|
function setDisplayTitle() {
|
||||||
|
const { title, modelValue, options, valueKey, labelKey } = props
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
displayTitle.value = title
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for (let i = 0, len = options.length; i < len; i++) {
|
||||||
|
if (modelValue === options[i][valueKey]) {
|
||||||
|
displayTitle.value = options[i][labelKey]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.error('[wot-design] warning(wd-drop-menu-item): no value is matched in the options option.')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父组件更改子组件内部
|
||||||
|
* @param show
|
||||||
|
*/
|
||||||
|
function setShowPop(show: boolean) {
|
||||||
|
showPop.value = show
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟单选操作 默认根据 value 选中操作
|
||||||
|
function choose(index: number) {
|
||||||
|
if (props.disabled) return
|
||||||
|
const { valueKey } = props
|
||||||
|
const item = props.options[index]
|
||||||
|
emit('update:modelValue', item[valueKey] !== '' && item[valueKey] !== undefined ? item[valueKey] : item)
|
||||||
|
close()
|
||||||
|
emit('change', {
|
||||||
|
value: item[valueKey] !== '' && item[valueKey] !== undefined ? item[valueKey] : item,
|
||||||
|
selectedItem: item
|
||||||
|
})
|
||||||
|
parent.$.exposed.updateTitle()
|
||||||
|
}
|
||||||
|
// 外部关闭弹出框
|
||||||
|
function close() {
|
||||||
|
showPop.value = false
|
||||||
|
parent.$.exposed.fold()
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionStyle = computed(() => {
|
||||||
|
let style: string = ''
|
||||||
|
if (showPop.value) {
|
||||||
|
style =
|
||||||
|
parent.direction === 'down'
|
||||||
|
? `top: calc(var(--window-top) + ${parent.$.exposed.offset.value}px); bottom: 0;`
|
||||||
|
: `top: 0; bottom: calc(var(--window-bottom) + ${parent.$.exposed.offset.value}px)`
|
||||||
|
} else {
|
||||||
|
style = ''
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
})
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
showWrapper.value = true
|
||||||
|
showPop.value = true
|
||||||
|
modal.value = parent.modal
|
||||||
|
duration.value = parent.duration
|
||||||
|
closeOnClickModal.value = parent.closeOnClickModal
|
||||||
|
position.value = parent.direction === 'down' ? 'top' : 'bottom'
|
||||||
|
emit('open')
|
||||||
|
}
|
||||||
|
function onPopupClose() {
|
||||||
|
showWrapper.value = false
|
||||||
|
emit('closed')
|
||||||
|
}
|
||||||
|
function handleOpen() {
|
||||||
|
emit('open')
|
||||||
|
}
|
||||||
|
function handleOpened() {
|
||||||
|
emit('opened')
|
||||||
|
}
|
||||||
|
function handleClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ setShowPop, open, close, displayTitle })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(drop-menu) {
|
||||||
|
color: $-dark-color;
|
||||||
|
@include e(list) {
|
||||||
|
background-color: $-dark-background2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(item) {
|
||||||
|
@include when(disabled) {
|
||||||
|
color: $-dark-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(drop-menu) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: $-drop-menu-color;
|
||||||
|
font-size: $-drop-menu-fs;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
@include e(list) {
|
||||||
|
display: flex;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
@include e(item) {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: $-drop-menu-height;
|
||||||
|
line-height: $-drop-menu-height;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@include when(active) {
|
||||||
|
font-weight: $-fw-medium;
|
||||||
|
|
||||||
|
.wd-drop-menu__item-title::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
:deep(.wd-drop-menu__arrow) {
|
||||||
|
transform: scale(0.6) rotate(-180deg);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include when(disabled) {
|
||||||
|
color: $-drop-menu-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(item-title) {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0 $-drop-menu-side-padding;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
content: '';
|
||||||
|
width: 19px;
|
||||||
|
height: $-drop-menu-line-height;
|
||||||
|
bottom: 6px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
background: $-drop-menu-line-color;
|
||||||
|
border-radius: $-drop-menu-line-height;
|
||||||
|
transition: opacity .15s;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(item-title-text) {
|
||||||
|
position: relative;
|
||||||
|
@include lineEllipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(arrow) {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
top: 0;
|
||||||
|
right: -4px;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
transform: scale(0.6);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,154 @@
|
|||||||
|
@import "../common/abstracts/variable";
|
||||||
|
@import "../common/abstracts/mixin";
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(fab) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(fab) {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
|
||||||
|
@include edeep(trigger) {
|
||||||
|
min-width: auto !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: $-fab-trigger-width !important;
|
||||||
|
height: $-fab-trigger-height !important;
|
||||||
|
border-radius: calc($-fab-trigger-height / 2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep() {
|
||||||
|
@include e(actions) {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: $-fab-actions-padding 0;
|
||||||
|
|
||||||
|
@include m(left, right) {
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
padding: 0 $-fab-actions-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(left) {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
right: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(right) {
|
||||||
|
flex-direction: row;
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(top, bottom) {
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(top) {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
bottom: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(bottom) {
|
||||||
|
flex-direction: column;
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动画
|
||||||
|
@include e(transition-enter-active, transition-leave-active) {
|
||||||
|
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include e(transition-enter) {
|
||||||
|
@include m(top) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(bottom) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(left) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(right) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-40px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include e(transition-leave-to) {
|
||||||
|
@include m(top) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(bottom) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(left) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(right) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-40px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@include edeep(icon) {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(left-top) {
|
||||||
|
top: $-fab-top;
|
||||||
|
left: $-fab-left;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
top: calc($-fab-top + var(--window-top));
|
||||||
|
left: calc($-fab-left + var(--window-left));
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(right-top) {
|
||||||
|
top: $-fab-top;
|
||||||
|
right: $-fab-right;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
top: calc($-fab-top + var(--window-top));
|
||||||
|
right: calc($-fab-right + var(--window-right));
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(left-bottom) {
|
||||||
|
bottom: $-fab-bottom;
|
||||||
|
left: $-fab-left;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
bottom: calc($-fab-bottom + var(--window-bottom));
|
||||||
|
left: calc($-fab-left + var(--window-left));
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
@include m(right-bottom) {
|
||||||
|
bottom: $-fab-bottom;
|
||||||
|
right: $-fab-right;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
bottom: calc($-fab-bottom + var(--window-bottom));
|
||||||
|
right: calc($-fab-right + var(--window-right));
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
@import '../common/abstracts/variable';
|
||||||
|
@import '../common/abstracts/mixin';
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(form-item) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@include bdeep(form-item) {
|
||||||
|
@include e(error-message){
|
||||||
|
color: $-form-item-error-message-color;
|
||||||
|
font-size: $-form-item-error-message-font-size;
|
||||||
|
line-height: $-form-item-error-message-line-height;
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: weisheng
|
||||||
|
* @Date: 2023-12-14 11:21:58
|
||||||
|
* @LastEditTime: 2023-12-17 15:16:03
|
||||||
|
* @LastEditors: weisheng
|
||||||
|
* @Description:
|
||||||
|
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-form-item\wd-form-item.vue
|
||||||
|
* 记得注释
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<wd-cell
|
||||||
|
custom-class="wd-form-item"
|
||||||
|
:required="required"
|
||||||
|
:title="label"
|
||||||
|
:center="center"
|
||||||
|
:border="border"
|
||||||
|
:title-width="labelWidth"
|
||||||
|
:is-link="isLink"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
<view v-if="errorMessage" class="wd-form-item__error-message">{{ errorMessage }}</view>
|
||||||
|
</wd-cell>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'wd-form-item',
|
||||||
|
options: {
|
||||||
|
addGlobalClass: true,
|
||||||
|
virtualHost: true,
|
||||||
|
styleIsolation: 'shared'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useParent } from '../composables/useParent'
|
||||||
|
import WdCell from '../wd-cell/wd-cell.vue'
|
||||||
|
import { FORM_KEY, FormItemRule } from '../wd-form/types'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
prop: string
|
||||||
|
rules?: FormItemRule[]
|
||||||
|
required?: boolean
|
||||||
|
center?: boolean
|
||||||
|
label?: string
|
||||||
|
labelWidth?: string
|
||||||
|
isLink?: boolean
|
||||||
|
customClass?: string
|
||||||
|
customStyle?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
rules: () => [],
|
||||||
|
center: false,
|
||||||
|
labelWidth: '100px',
|
||||||
|
customClass: '',
|
||||||
|
customStyle: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const { parent: form, index } = useParent(FORM_KEY)
|
||||||
|
|
||||||
|
const errorMessage = computed(() => {
|
||||||
|
if (form && props.prop && form.errorMessages && form.errorMessages[props.prop]) {
|
||||||
|
return form.errorMessages[props.prop]
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const border = computed(() => {
|
||||||
|
if (index.value > 0 && form && form.border) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import './index.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
@import "../common/abstracts/variable";
|
||||||
|
@import "../common/abstracts/mixin";
|
||||||
|
|
||||||
|
.wot-theme-dark {
|
||||||
|
@include b(form) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include b(form) {
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue