修改目录结构;调整组件路径;访客邀约页面;

This commit is contained in:
weiwei committed 2025-07-29 19:34:46 +08:00
1 parent 3d6ea75b46
commit a813da33ee
16 files changed
+504 -532

No files matched your search

@@ -1,8 +1,17 @@
<script setup lang="ts">
import { computed, ref, onMounted, watch, PropType } from "vue";
import { arrayNumberValid, getUid, arrayNumberValidByStyleMP, arrayNumberValidByStyleBorderColor, arrayNumberValidByStyleBorderStyle, covetUniNumber, linearValid, getUnit } from "../../libs/tool";
import { useTmConfig } from "../../libs/config";
import { getDefaultColor, getDefaultColorObj, getOutlineColorObj, getTextColorObj, getThinColorObj } from "../../libs/colors";
import { computed, ref, onMounted, watch } from "vue"
import {
arrayNumberValid,
getUid,
arrayNumberValidByStyleMP,
arrayNumberValidByStyleBorderColor,
arrayNumberValidByStyleBorderStyle,
covetUniNumber,
linearValid,
getUnit,
} from "../../libs/tool"
import { useTmConfig } from "../../libs/config"
import { getDefaultColor, getDefaultColorObj, getOutlineColorObj, getTextColorObj, getThinColorObj } from "../../libs/colors"
/**
* @displayName 开关
* @exportName tm-switch
@@ -13,359 +22,376 @@ import { getDefaultColor, getDefaultColorObj, getOutlineColorObj, getTextColorOb
| --- | --- | --- | --- |
| ☑️| ☑️ | ☑️ | ☑️ | ☑️ | 1.0.0 |
*/
defineOptions({ name: 'TmSwitch' });
defineOptions({ name: "TmSwitch" })
const { config } = useTmConfig()
const props = defineProps({
/**
* 激活时的背景色,空值时取全局的值。
*/
color: {
type: String,
default: ""
},
/**
* 未激活时的背景
*/
bgColor: {
type: String,
default: "info"
},
/**
* 未激活时的暗黑背景
* 空取inputDarkColor
*/
darkBgColor: {
type: String,
default: ""
},
/**
* 按钮的背景色
*/
btnColor: {
type: String,
default: "white"
},
/**
* 尺寸
*/
size: {
type: String as PropType<"small" | "normal" | "large">,
default: "normal"
},
/**
* 间隙,px单位
*/
space: {
type: [Number, String],
default: "2px"
},
/**
* 当前打开的状态,默认为false
* 等同v-model=""
*/
modelValue: {
type: Boolean,
default: false
},
/**
* 是否禁用
*/
disabled: {
type: Boolean,
default: false
},
/**
* 是否加载中
*/
loading: {
type: Boolean,
default: false
},
/**
* 开关文字数组第一个为开,后一个为关
*/
label: {
type: Array as PropType<string[]>,
default: (): string[] => [],
validator(val: string[]): boolean {
if (!Array.isArray(val)) return false;
if (val.length == 0) return true;
if (val.length != 2) {
console.error("x:必须长度为2")
return false;
}
return true
}
},
/**
* 圆角。空值时取全局值。
*/
round: {
type: [String, Number],
default: ""
}
});
/**
* 激活时的背景色,空值时取全局的值。
*/
color: {
type: String,
default: "",
},
/**
* 未激活时的背景
*/
bgColor: {
type: String,
default: "info",
},
/**
* 未激活时的暗黑背景
* 空取inputDarkColor
*/
darkBgColor: {
type: String,
default: "",
},
/**
* 按钮的背景色
*/
btnColor: {
type: String,
default: "white",
},
/**
* 尺寸
*/
size: {
type: String,
default: "normal",
},
/**
* 间隙,px单位
*/
space: {
type: [Number, String],
default: "2px",
},
/**
* 当前打开的状态,默认为false
* 等同v-model=""
*/
modelValue: {
type: Boolean,
default: false,
},
/**
* 是否禁用
*/
disabled: {
type: Boolean,
default: false,
},
/**
* 是否加载中
*/
loading: {
type: Boolean,
default: false,
},
/**
* 开关文字数组第一个为开,后一个为关
*/
label: {
type: Array,
default: (): string[] => [],
validator(val: string[]): boolean {
if (!Array.isArray(val)) return false
if (val.length == 0) return true
if (val.length != 2) {
console.error("x:必须长度为2")
return false
}
return true
},
},
/**
* 圆角。空值时取全局值。
*/
round: {
type: [String, Number],
default: "",
},
})
const emit = defineEmits<{
/**
* 状态变换时触发。
* @param status - 当前的开关状态
*/
(e: 'change', status: boolean): void;
/**
* 组件被点击时触发。
* @param status - 当前的开关状态,这里的状态是在变更前。
*/
(e: 'click', status: boolean): void;
(e: 'update:modelValue', value: boolean): void;
}>();
/**
* 状态变换时触发。
* @param status - 当前的开关状态
*/
(e: "change", status: boolean): void
/**
* 组件被点击时触发。
* @param status - 当前的开关状态,这里的状态是在变更前。
*/
(e: "click", status: boolean): void
(e: "update:modelValue", value: boolean): void
}>()
const id = ref(`tmSwitch${getUid()}`);
const boxwidth = ref(0);
const boxheight = ref(0);
const opened = ref(false);
const id = ref(`tmSwitch${getUid()}`)
const boxwidth = ref(0)
const boxheight = ref(0)
const opened = ref(false)
onMounted(() => {
opened.value = props.modelValue;
getNodes();
});
opened.value = props.modelValue
getNodes()
})
const _round = computed((): string => {
if (props.round == "") {
return covetUniNumber(config.switchRadius, config.unit)
}
return covetUniNumber(props.round, config.unit)
});
if (props.round == "") {
return covetUniNumber(config.switchRadius, config.unit)
}
return covetUniNumber(props.round, config.unit)
})
const _bgColor = computed((): string => {
if (config.mode == 'dark') {
if (props.darkBgColor != '') return props.darkBgColor
return config.inputDarkColor;
}
return getDefaultColor(props.bgColor)
});
if (config.mode == "dark") {
if (props.darkBgColor != "") return props.darkBgColor
return config.inputDarkColor
}
return getDefaultColor(props.bgColor)
})
const _activeBgColor = computed((): string => {
if (props.color == "") {
return getDefaultColor(config.color)
}
return getDefaultColor(props.color)
});
if (props.color == "") {
return getDefaultColor(config.color)
}
return getDefaultColor(props.color)
})
const _btnColor = computed((): string => {
return getDefaultColor(props.btnColor)
});
return getDefaultColor(props.btnColor)
})
const _size = computed((): string => {
if (props.size == "small") return "44rpx"
if (props.size == "large") return "76rpx"
return "60rpx"
});
if (props.size == "small") return "44rpx"
if (props.size == "large") return "76rpx"
return "60rpx"
})
const _fontSize = computed((): string => {
if (props.size == "small") return "20rpx"
if (props.size == "large") return "24rpx"
return "22rpx"
});
if (props.size == "small") return "20rpx"
if (props.size == "large") return "24rpx"
return "22rpx"
})
const _sizeWidth = computed((): string => {
if (props.size == "small") return "88rpx"
if (props.size == "large") return "152rpx"
return "120rpx"
});
if (props.size == "small") return "88rpx"
if (props.size == "large") return "152rpx"
return "120rpx"
})
const _space = computed((): number => {
let space = covetUniNumber(props.space)
let spaceUnit = getUnit(space)
let spacenumber = parseInt(space)
if (spaceUnit == 'rpx') {
spacenumber = uni.upx2px(parseInt(space))
}
let space = covetUniNumber(props.space)
let spaceUnit = getUnit(space)
let spacenumber = parseInt(space)
if (spaceUnit == "rpx") {
spacenumber = uni.upx2px(parseInt(space))
}
return spacenumber
});
return spacenumber
})
const _contentWidth = computed((): number => {
return boxwidth.value - _space.value * 2
});
return boxwidth.value - _space.value * 2
})
const _contentHeight = computed((): number => {
return boxheight.value - _space.value * 2
});
return boxheight.value - _space.value * 2
})
const _maxLeftPos = computed((): number => {
return _contentWidth.value - _contentHeight.value
});
return _contentWidth.value - _contentHeight.value
})
const _label = computed((): string[] => {
return props.label;
});
return props.label
})
const _loading = computed((): boolean => {
return props.loading;
});
return props.loading
})
const _disabled = computed((): boolean => {
return props.disabled;
});
return props.disabled
})
const _animationFun = computed((): string => {
return config.animation
});
return config.animation
})
watch(() => props.modelValue, (newvalue: boolean) => {
if (newvalue != opened.value) {
opened.value = newvalue;
}
});
watch(
() => props.modelValue,
(newvalue: boolean) => {
if (newvalue != opened.value) {
opened.value = newvalue
}
},
)
function onClick() {
/**
* 组件被点击时触发。
* @param status {boolean} 当前的开关状态,这里的状态是在变更前。
*/
emit("click", opened.value)
if (_loading.value || _disabled.value) return;
opened.value = !opened.value
/**
* 状态变换时触发。
* @param status {boolean} 当前的开关状态
*/
emit("change", opened.value)
/**
* 等同v-model=""
*/
emit("update:modelValue", opened.value)
/**
* 组件被点击时触发。
* @param status {boolean} 当前的开关状态,这里的状态是在变更前。
*/
emit("click", opened.value)
if (_loading.value || _disabled.value) return
opened.value = !opened.value
/**
* 状态变换时触发。
* @param status {boolean} 当前的开关状态
*/
emit("change", opened.value)
/**
* 等同v-model=""
*/
emit("update:modelValue", opened.value)
}
function getNodes() {
let width = covetUniNumber(_sizeWidth.value)
let height = covetUniNumber(_size.value)
let widthUnit = getUnit(width)
let heightUnit = getUnit(height)
if (widthUnit == 'rpx') {
width = uni.upx2px(parseInt(width)) + ''
}
if (heightUnit == 'rpx') {
height = uni.upx2px(parseInt(height)) + ''
}
boxwidth.value = parseInt(width);
boxheight.value = parseInt(height);
let width = covetUniNumber(_sizeWidth.value)
let height = covetUniNumber(_size.value)
let widthUnit = getUnit(width)
let heightUnit = getUnit(height)
if (widthUnit == "rpx") {
width = uni.upx2px(parseInt(width)) + ""
}
if (heightUnit == "rpx") {
height = uni.upx2px(parseInt(height)) + ""
}
boxwidth.value = parseInt(width)
boxheight.value = parseInt(height)
}
</script>
<script lang="ts">
export default {
options: {
styleIsolation: "apply-shared",
virtualHost: true,
addGlobalClass: true,
multipleSlots: true,
},
};
options: {
styleIsolation: "apply-shared",
virtualHost: true,
addGlobalClass: true,
multipleSlots: true,
},
}
</script>
<template>
<view @click="onClick" :id="id" class="tmSwitch" ref="tmSwitch" :style="{
height: boxheight+'px',
width: boxwidth+'px',
backgroundColor: _bgColor,
borderRadius: _round
}">
<view :class="[_disabled ? 'tmSwitchDisabled' : '', opened ? 'tmSwitchBgOn' : 'tmSwitchOff']" class="tmSwitchBg"
:style="{ backgroundColor: _activeBgColor, borderRadius: _round, 'transition-timing-function': _animationFun }">
</view>
<view :class="[_disabled ? 'tmSwitchDisabled' : '']" class="tmSwitchWrap" :style="{
left: _space + 'px',
top: _space + 'px',
width: _contentWidth + 'px',
height: _contentHeight + 'px',
borderRadius: _round
}">
<view v-if="_label.length == 2" class="tmSwitchText">
<text class="tmSwitchTextLeft" :style="{ fontSize: _fontSize }">{{ !opened ? '' : _label[0] }}</text>
<text class="tmSwitchTextRight" :style="{ fontSize: _fontSize }">{{ opened ? '' : _label[1] }}</text>
</view>
<view class="tmSwitchBtn" :style="{
width: _contentHeight + 'px',
height: _contentHeight + 'px',
transform: `translateX(${opened ? _maxLeftPos : 0}px)`,
backgroundColor: _btnColor,
borderRadius: _round,
'transition-timing-function': _animationFun
}">
<tm-icon v-if="_loading" :spin="true" size="24" name="loader-line" :color="_activeBgColor"></tm-icon>
</view>
</view>
</view>
<view
@click="onClick"
:id="id"
class="tmSwitch"
ref="tmSwitch"
:style="{
height: boxheight + 'px',
width: boxwidth + 'px',
backgroundColor: _bgColor,
borderRadius: _round,
}"
>
<view
:class="[_disabled ? 'tmSwitchDisabled' : '', opened ? 'tmSwitchBgOn' : 'tmSwitchOff']"
class="tmSwitchBg"
:style="{ backgroundColor: _activeBgColor, borderRadius: _round, 'transition-timing-function': _animationFun }"
>
</view>
<view
:class="[_disabled ? 'tmSwitchDisabled' : '']"
class="tmSwitchWrap"
:style="{
left: _space + 'px',
top: _space + 'px',
width: _contentWidth + 'px',
height: _contentHeight + 'px',
borderRadius: _round,
}"
>
<view v-if="_label.length == 2" class="tmSwitchText">
<text class="tmSwitchTextLeft" :style="{ fontSize: _fontSize }">{{ !opened ? "" : _label[0] }}</text>
<text class="tmSwitchTextRight" :style="{ fontSize: _fontSize }">{{ opened ? "" : _label[1] }}</text>
</view>
<view
class="tmSwitchBtn"
:style="{
width: _contentHeight + 'px',
height: _contentHeight + 'px',
transform: `translateX(${opened ? _maxLeftPos : 0}px)`,
backgroundColor: _btnColor,
borderRadius: _round,
'transition-timing-function': _animationFun,
}"
>
<tm-icon v-if="_loading" :spin="true" size="24" name="loader-line" :color="_activeBgColor"></tm-icon>
</view>
</view>
</view>
</template>
<style scoped>
.tmSwitchDisabled {
opacity: 0.7;
cursor: no-drop !important;
overflow: hidden;
opacity: 0.7;
cursor: no-drop !important;
overflow: hidden;
}
.tmSwitchTextLeft {
color: white;
color: white;
}
.tmSwitchTextRight {
color: #acacac;
color: #acacac;
}
.tmSwitch {
height: 64rpx;
cursor: pointer;
display: inline-flex;
position: relative;
box-sizing: border-box;
height: 64rpx;
cursor: pointer;
display: inline-flex;
position: relative;
box-sizing: border-box;
}
.tmSwitchBg {
width: 100%;
height: 100%;
transition-duration: 350ms;
transition-property: opacity, transform;
box-sizing: border-box;
width: 100%;
height: 100%;
transition-duration: 350ms;
transition-property: opacity, transform;
box-sizing: border-box;
}
.tmSwitchBgOn {
opacity: 1;
transform: scale(1);
opacity: 1;
transform: scale(1);
}
.tmSwitchOff {
opacity: 0;
transform: scale(0.9);
opacity: 0;
transform: scale(0.9);
}
.tmSwitchWrap {
position: absolute;
position: absolute;
}
.tmSwitchText {
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 0 12%;
box-sizing: border-box;
width: 100%;
height: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 0 12%;
box-sizing: border-box;
}
.tmSwitchBtn {
position: absolute;
transition-duration: 350ms;
left: 0px;
transition-property: transform;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
top: 0px;
position: absolute;
transition-duration: 350ms;
left: 0px;
transition-property: transform;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
top: 0px;
}
</style>
</style>