更新:登录功能

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,204 @@
@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;
&:not(.wd-action-sheet__action--disabled):not(.wd-action-sheet__action--loading):active {
background: $-dark-background4;
}
@include m(disabled) {
color: $-dark-color-gray;
}
}
@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;
}
&:not(&--disabled):not(&--loading):active {
background: $-action-sheet-active-color;
}
@include m(disabled) {
color: $-action-sheet-disabled-color;
cursor: not-allowed;
}
@include m(loading) {
display: flex;
align-items: center;
justify-content: center;
line-height: initial;
}
}
@include edeep(action-loading){
width: $-action-sheet-loading-size;
height: $-action-sheet-loading-size;
}
@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;
}
}

View File

@@ -0,0 +1,118 @@
import type { ExtractPropTypes } from 'vue'
import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeRequiredProp, makeStringProp } from '../common/props'
export type Action = {
/**
* 选项名称
*/
name: string
/**
* 描述信息
*/
subname?: string
/**
* 颜色
*/
color?: string
/**
* 禁用
*/
disabled?: boolean
/**
* 加载中状态
*/
loading?: boolean
}
export type Panel = {
/**
* 图片地址
*/
iconUrl: string
/**
* 标题内容
*/
title: string
}
export const actionSheetProps = {
...baseProps,
/**
* header 头部样式
* @default ''
* @type {string}
*/
customHeaderClass: makeStringProp(''),
/**
* 设置菜单显示隐藏
* @default false
* @type {boolean}
*/
modelValue: { ...makeBooleanProp(false), ...makeRequiredProp(Boolean) },
/**
* 菜单选项
* @default []
* @type {Action[]}
*/
actions: makeArrayProp<Action>(),
/**
* 自定义面板项,可以为字符串数组,也可以为对象数组,如果为二维数组,则为多行展示
* @default []
* @type {Array<Panel | Panel[]>}
*/
panels: makeArrayProp<Panel | Panel[]>(),
/**
* 标题
* @type {string}
*/
title: String,
/**
* 取消按钮文案
* @type {string}
*/
cancelText: String,
/**
* 点击选项后是否关闭菜单
* @default true
* @type {boolean}
*/
closeOnClickAction: makeBooleanProp(true),
/**
* 点击遮罩是否关闭
* @default true
* @type {boolean}
*/
closeOnClickModal: makeBooleanProp(true),
/**
* 弹框动画持续时间
* @default 200
* @type {number}
*/
duration: makeNumberProp(200),
/**
* 菜单层级
* @default 10
* @type {number}
*/
zIndex: makeNumberProp(10),
/**
* 弹层内容懒渲染,触发展示时才渲染内容
* @default true
* @type {boolean}
*/
lazyRender: makeBooleanProp(true),
/**
* 弹出面板是否设置底部安全距离iphone X 类型的机型)
* @default true
* @type {boolean}
*/
safeAreaInsetBottom: makeBooleanProp(true),
/**
* 是否从页面中脱离出来,用于解决各种 fixed 失效问题 (H5: teleport, APP: renderjs, 小程序: root-portal)
* 类型boolean
* 默认值false
*/
rootPortal: makeBooleanProp(false)
}
export type ActionSheetProps = ExtractPropTypes<typeof actionSheetProps>

View File

@@ -0,0 +1,155 @@
<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"
:root-portal="rootPortal"
@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 custom-class="`wd-action-sheet__action-loading" v-if="action.loading" />
<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 wdPopup from '../wd-popup/wd-popup.vue'
import wdIcon from '../wd-icon/wd-icon.vue'
import wdLoading from '../wd-loading/wd-loading.vue'
import { watch, ref } from 'vue'
import { actionSheetProps, type Panel } from './types'
import { isArray } from '../common/util'
const props = defineProps(actionSheetProps)
const emit = defineEmits(['select', 'click-modal', 'cancel', 'closed', 'close', 'open', 'opened', 'update:modelValue'])
const formatPanels = ref<Array<Panel> | 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 }
)
function isPanelArray() {
return props.panels.length && !isArray(props.panels[0])
}
function computedValue() {
formatPanels.value = isPanelArray() ? [props.panels as Panel[]] : (props.panels as Panel[][])
}
function select(rowIndex: number, type: 'action' | 'panels', colIndex?: number) {
if (type === 'action') {
if (props.actions[rowIndex].disabled || props.actions[rowIndex].loading) {
return
}
emit('select', {
item: props.actions[rowIndex],
index: rowIndex
})
} else if (isPanelArray()) {
emit('select', {
item: props.panels[Number(colIndex)],
index: colIndex
})
} else {
emit('select', {
item: (props.panels as Panel[][])[rowIndex][Number(colIndex)],
rowIndex,
colIndex
})
}
if (props.closeOnClickAction) {
close()
}
}
function handleClickModal() {
emit('click-modal')
}
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>