更新:登录功能

This commit is contained in:
2025-11-04 12:37:04 +08:00
commit a21fb92916
897 changed files with 51500 additions and 0 deletions

View File

@@ -0,0 +1,101 @@
@import './../common/abstracts/_mixin.scss';
@import './../common/abstracts/variable.scss';
.wot-theme-dark {
@include b(segmented) {
background: $-dark-background2;
@include e(item) {
color: $-dark-color3;
@include when(active) {
color: $-dark-color;
@include when(disabled) {
color: $-dark-color3;
}
}
@include when(disabled) {
color: $-dark-color-gray;
}
@include m(active) {
background-color: $-color-theme;
@include when(disabled) {
opacity: 0.6;
}
}
}
}
}
@include b(segmented) {
position: relative;
display: flex;
align-items: stretch;
justify-items: flex-start;
width: 100%;
background-color: $-segmented-item-bg-color;
padding: $-segmented-padding;
border-radius: 4px;
box-sizing: border-box;
@include e(item) {
position: relative;
text-align: center;
border-radius: 4px;
flex: 1;
min-width: 0;
z-index: 1;
min-height: 28px;
line-height: 28px;
padding: 0 12px;
font-size: 14px;
color: $-segmented-item-color;
font-weight: 400;
@include when(active) {
font-weight: 550;
}
@include when(large) {
min-height: 32px;
line-height: 32px;
padding: 0 12px;
font-size: 16px;
}
@include when(small) {
min-height: 24px;
line-height: 24px;
padding: 0 7px;
font-size: 12px;
}
@include when(disabled) {
cursor: no-drop;
color: $-segmented-item-disabled-color;
}
@include m(active) {
background-color: $-segmented-item-acitve-bg;
border-radius: 4px;
height: calc(100% - $-segmented-padding * 2);
@include when(disabled) {
opacity: 0.8;
}
}
}
@include e(item-label) {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}

View File

@@ -0,0 +1,80 @@
/*
* @Author: weisheng
* @Date: 2024-03-18 11:22:03
* @LastEditTime: 2024-11-24 23:04:55
* @LastEditors: weisheng
* @Description:
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-segmented/types.ts
* 记得注释
*/
import type { ComponentPublicInstance, ExtractPropTypes, PropType } from 'vue'
import { baseProps, makeBooleanProp, makeRequiredProp, makeStringProp } from '../common/props'
export type SegmentedType = 'large' | 'middle' | 'small'
export interface SegmentedOption {
value: string | number // 选中值
disabled?: boolean // 是否禁用
payload?: any // 更多数据
}
export const segmentedProps = {
...baseProps,
/**
* 当前选中的值
* 类型: string | number
* 最低版本: 0.1.23
*/
value: makeRequiredProp([String, Number]),
/**
* 是否禁用分段器
* 类型: boolean
* 默认值: false
* 最低版本: 0.1.23
*/
disabled: makeBooleanProp(false),
/**
* 控件尺寸
* 类型: string
* 可选值: 'large' | 'middle' | 'small'
* 默认值: 'middle'
* 最低版本: 0.1.23
*/
size: makeStringProp<SegmentedType>('middle'),
/**
* 数据集合
* 类型: string[] | number[] | SegmentedOption[]
* 必需: 是
* 默认值: []
* 最低版本: 0.1.23
*/
options: {
type: Array as PropType<string[] | number[] | SegmentedOption[]>,
required: true,
default: () => []
},
/**
* 切换选项时是否振动
* 类型: boolean
* 默认值: false
* 最低版本: 0.1.23
*/
vibrateShort: makeBooleanProp(false)
}
export type SegmentedExpose = {
/**
* 更新滑块偏移量
* @param animation 是否开启动画,默认开启
*/
updateActiveStyle: (animation?: boolean) => void
}
export type SegmentedProps = ExtractPropTypes<typeof segmentedProps>
export type SegmentedInstance = ComponentPublicInstance<SegmentedProps, SegmentedExpose>

View File

@@ -0,0 +1,143 @@
<template>
<view :class="`wd-segmented ${customClass}`" :style="customStyle">
<view
:class="`wd-segmented__item is-${size} ${state.activeIndex === index ? 'is-active' : ''} ${
disabled || (isObj(option) ? option.disabled : false) ? 'is-disabled' : ''
}`"
@click="handleClick(option, index)"
v-for="(option, index) in options"
:key="index"
>
<view class="wd-segmented__item-label">
<slot name="label" v-if="$slots.label" :option="isObj(option) ? option : { value: option }"></slot>
<template v-else>
{{ isObj(option) ? option.value : option }}
</template>
</view>
</view>
<view :class="`wd-segmented__item--active ${activeDisabled ? 'is-disabled' : ''}`" :style="state.activeStyle"></view>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-segmented',
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: 'shared'
}
}
</script>
<script setup lang="ts">
import { computed, getCurrentInstance, onMounted, reactive, watch } from 'vue'
import { getRect, isObj, objToStyle, addUnit, pause, isEqual } from '../common/util'
import type { CSSProperties } from 'vue'
import { segmentedProps, type SegmentedExpose, type SegmentedOption } from './types'
const $item = '.wd-segmented__item'
const props = defineProps(segmentedProps)
const emit = defineEmits(['update:value', 'change', 'click'])
const state = reactive({
activeIndex: 0, // 选中项
activeStyle: '' // 选中样式
})
const activeDisabled = computed(() => {
return props.disabled || (props.options[0] && isObj(props.options[0]) ? props.options[0].disabled : false)
})
watch(
() => props.value,
() => {
updateCurrentIndex()
updateActiveStyle()
if (props.vibrateShort) {
uni.vibrateShort({})
}
},
{
immediate: false
}
)
const { proxy } = getCurrentInstance() as any
onMounted(async () => {
updateCurrentIndex()
await pause()
updateActiveStyle(false)
})
/**
* 更新滑块偏移量
*
*/
function updateActiveStyle(animation: boolean = true) {
getRect($item, true, proxy).then((rects) => {
const rect = rects[state.activeIndex]
const style: CSSProperties = {
position: 'absolute',
width: addUnit(rect.width!),
'z-index': 0
}
const left = rects.slice(0, state.activeIndex).reduce((prev, curr) => prev + Number(curr.width), 0)
if (left) {
style.transform = `translateX(${left}px)`
}
if (animation) {
style.transition = 'all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1)'
}
state.activeStyle = objToStyle(style)
})
}
/**
* 更新值
*/
function updateValue(newValue: string | number, option: string | number | SegmentedOption) {
if (!isEqual(newValue, props.value)) {
emit('update:value', newValue)
emit('change', isObj(option) ? option : { value: newValue })
}
}
/**
* 更新当前下标
*/
function updateCurrentIndex() {
const index = props.options.findIndex((option: string | number | SegmentedOption) => {
const value = isObj(option) ? option.value : option
return isEqual(value, props.value)
})
if (index >= 0) {
state.activeIndex = index
} else {
const value = isObj(props.options[0]) ? props.options[0].value : props.options[0]
updateValue(value, props.options[0])
}
}
function handleClick(option: string | number | SegmentedOption, index: number) {
const disabled = props.disabled || (isObj(option) ? option.disabled : false)
if (disabled) {
return
}
const value = isObj(option) ? option.value : option
state.activeIndex = index
updateActiveStyle()
updateValue(value, option)
emit('click', isObj(option) ? option : { value })
}
defineExpose<SegmentedExpose>({
updateActiveStyle
})
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>