Initial commit of akmon project

This commit is contained in:
2026-01-20 08:04:15 +08:00
commit 77a2bab985
1309 changed files with 343305 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
@import '~@/uni_modules/lime-style/index.scss';
$prefix: l !default;
$item: #{$prefix}-picker-item;
$picker-group-height: create-var(picker-group-height, 400rpx);
$picker-indicator-bg-color: create-var(picker-indicator-bg-color, $fill-4);
$picker-indicator-border-radius: create-var(picker-indicator-border-radius, 12rpx);
$picker-item-height: create-var(picker-item-height, 50px);
$picker-item-active-color: create-var(picker-item-active-color, $text-color-1);
$picker-item-active-font-weight: create-var(picker-item-active-font-weight, 700);
$picker-item-color: create-var(picker-item-color, $text-color-1);
$picker-item-font-size: create-var(picker-item-font-size, $font-size-md);
/* #ifndef APP-ANDROID || APP-IOS || APP-HARMONY */
:host {
flex: 1;
display: flex;
}
/* #endif */
.#{$item} {
&__group {
/* #ifdef WEB */
:deep(.uni-picker-view-content) {
// 300ms
transition-duration: var(--picker-duration, 0);
}
/* #endif */
flex: 1;
// height: $picker-group-height;
&-item {
height: $picker-item-height;
line-height: $picker-item-height;
text-align: center;
/* #ifndef APP-ANDROID || APP-IOS || APP-HARMONY */
display: flex;
justify-content: center;
/* #endif */
transition-duration: 100ms;
transition-property: font-weight, color;
transition-timing-function: linear;
font-weight: 400;
color: $picker-item-color;
font-size: $picker-item-font-size;
white-space: nowrap;
&--active {
color: $picker-item-active-color;
font-weight: $picker-item-active-font-weight;
}
}
}
&__indicator {
// position: absolute;
left: 0rpx;
right: 0rpx;
width: auto;
height: $picker-item-height;
// top: 144rpx;
pointer-events: none;
background-color: $picker-indicator-bg-color;
// border-radius: $picker-indicator-border-radius;
/* #ifndef APP-ANDROID || APP-IOS || APP-HARMONY */
&:after,&:before{
display: none;
}
/* #endif */
}
}

View File

@@ -0,0 +1,234 @@
<template>
<picker-view
class="l-picker-item__group"
:style="{opacity: options.length > 0 ? 1 : 0}"
:indicator-style="indicatorStyles"
:value="innerIndex"
@change="handlePick"
indicator-class="l-picker-item__indicator">
<picker-view-column class="l-picker-item__wrapper">
<!-- #ifdef APP-ANDROID -->
<view ref="itemRef"></view>
<!-- #endif -->
<!-- #ifndef APP-ANDROID -->
<text class="l-picker-item__group-item" v-for="(item, i) in options"
:style="[itemStyles, curIndex == i ? itemActiveStyles: {}]"
:class="{'l-picker-item__group-item--active': curIndex == i}" :key="item.value">{{item.label}}</text>
<!-- #endif -->
</picker-view-column>
</picker-view>
</template>
<script lang="uts" setup>
/**
* PickerItem 选择器子项组件
* @description 用于构建多列选择器的单个列项,通常作为 Picker 组件的子组件使用
* <br>插件类型LPickerItemComponentPublicInstance
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-picker
*
* @property {PickerColumnItem[]} options 当前列的选项列表(必填)
* @property {PickerValue} value 当前选中值
* @property {number} column 列索引标识从0开始计数
* @property {string | number} name 列名称标识符
*/
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
import { clamp } from '@/uni_modules/lime-shared/clamp'
import { PickerItemProps, ManageChildInList, OnPick, UpdateItems } from './type';
import { PickerColumnItem, PickerValue } from '../l-picker/type';
const instance = getCurrentInstance()!;
const props = withDefaults(defineProps<PickerItemProps>(), {
options: [] as PickerColumnItem[],
column: -1,
resetIndex: false
})
const picker = inject<LPickerComponentPublicInstance | null>('limePicker', null);
const pickerItemInstanceArray = inject<LPickerItemComponentPublicInstance[] | null>('limePickerItems', null);
const manageChildInList = inject<ManageChildInList | null>('limePickerManageChildInList', null);
manageChildInList?.(instance.proxy! as LPickerItemComponentPublicInstance, true)
const onPick = inject<OnPick | null>('limePickerOnPick', null);
const updateItems = inject<UpdateItems | null>('limePickerUpdateItems', null);
// web 如果初始是0 当数据加载后 无法指向0
// #ifdef WEB
const curIndex = ref(-1)
// #endif
// #ifndef WEB
const curIndex = ref(0)
// #endif
const curValue = ref<PickerValue | null>(props.value);
const column = computed(() : number => props.column != -1 ? props.column : pickerItemInstanceArray?.indexOf(instance.proxy! as LPickerItemComponentPublicInstance) ?? props.column);
const elementPosition = computed(() : boolean[] => {
const totalElements = pickerItemInstanceArray?.length ?? 0;
return [column.value == 0, column.value == totalElements - 1]
});
const innerIndex = computed(() : number[] => [curIndex.value])
const indicatorStyles = computed(() : string => {
const [isFirst, isLast] = elementPosition.value
let style = ``
if(isFirst) {
style+= 'border-top-left-radius:12rpx; border-bottom-left-radius:12rpx;'
}
if(isLast) {
style+= 'border-top-right-radius:12rpx; border-bottom-right-radius:12rpx;'
}
return `
${style}
height: ${picker?.itemHeight ?? '50px'};
background-color: rgba(0, 0, 0, 0.04); ${picker?.indicatorStyle}`
})
const itemStyles = computed(() : Map<string, any> => {
const style = new Map<string, any>();
if (picker?.itemColor != null) {
style.set('color', picker.itemColor!)
}
if (picker?.itemFontSize != null) {
style.set('font-size', picker.itemFontSize!)
}
if(picker?.itemHeight != null) {
style.set('line-height', picker.itemHeight!)
style.set('height', picker.itemHeight!)
}
return style
})
const itemActiveStyles = computed(() : Map<string, any> => {
const style = new Map<string, any>();
if (picker?.itemActiveColor != null) {
style.set('color', picker.itemActiveColor!)
}
if (picker?.itemActiveFontWeight != null) {
style.set('font-weight', picker.itemActiveFontWeight!)
}
return style
})
const getIndexByValue = (val : PickerValue | null) => {
let defaultIndex = 0;
if (val != null) {
defaultIndex = props.options.findIndex((item) => item.value == val);
}
return defaultIndex < 0 ? 0 : defaultIndex;
};
const setIndex = (index : number) => {
let lastIndex = curIndex.value
let _index = clamp(index, 0, props.options.length - 1)
if(props.options.length > _index) {
curIndex.value = _index;
curValue.value = props.options[_index].value
}
// #ifdef WEB
if(lastIndex == _index || lastIndex == -1) return
if (instance.proxy!.$el) {
const childs = Array.from(instance.proxy!.$el.parentElement.children).slice(column.value + 1);
childs.forEach((child) => {
(child as HTMLElement).style.setProperty('--picker-duration', '300ms');
setTimeout(function () {
(child as HTMLElement).style.setProperty('--picker-duration', '0ms');
}, 299);
})
}
// #endif
}
const setValue = (value : PickerValue | null) => {
if (value == curValue.value) return
curValue.value = value
const index = getIndexByValue(value)
setIndex(index)
}
const setOptions = () => { }
const setUpdateItems = () => {
const index = clamp(curIndex.value, 0, props.options.length - 1)
const curItem = props.options.length > index ? props.options[index] : null;
if (curItem == null) return
updateItems?.(curItem, index, column.value);
}
const handlePick = (e : UniPickerViewChangeEvent) => {
if(props.options.length == 0) return
const index = clamp(e.detail.value[0], 0, props.options.length - 1);
const curItem = props.options[index];
if(index == curIndex.value) return
setIndex(index)
onPick?.(curItem, index, column.value);
}
const stopValue = watch(() : PickerValue | null => props.value, (v : PickerValue | null) => {
setValue(v);
setUpdateItems();
}, { immediate: true })
// #ifdef APP-ANDROID
const itemRef = ref<UniElement | null>(null)
const updateItemStyle = () => {
if (itemRef.value != null) {
const ctx = itemRef.value!.getDrawableContext()!
const height = unitConvert(picker?.itemHeight ?? 50);
const fontSize = unitConvert(picker?.itemFontSize ?? '32rpx');
const rect = itemRef.value!.getBoundingClientRect()
const x = itemRef.value!.offsetWidth / 2;
const itemActiveFontWeight = picker?.itemActiveFontWeight ?? 700
itemRef.value!.style.setProperty('height', height * props.options.length);
ctx.reset()
ctx.fillStyle = picker?.itemActiveColor ?? 'rgba(0,0,0,0.88)';
ctx.font = `${fontSize}px`;
ctx.textAlign = 'center'
ctx.lineWidth = 0.5
props.options.forEach((item, index) => {
const y = height * index + fontSize + (height - fontSize) * 0.4; //(height - fontSize * 1.1)
ctx.fillText(item.label, x, y)
if (index == curIndex.value && itemActiveFontWeight > 600) {
ctx.strokeText(item.label, x, y)
}
})
ctx.update()
}
}
// 防止更新后尺寸不对
watchEffect(()=> {
if(curIndex.value > 0){}
nextTick(updateItemStyle)
})
const stop = watch(() : PickerColumnItem[] => props.options, (v : PickerColumnItem[], o : PickerColumnItem[]) => {
nextTick(updateItemStyle)
})
const resizeObserver = new UniResizeObserver((entries : Array<UniResizeObserverEntry>) => {
updateItemStyle()
})
const stopWatch = watch(():UniElement|null => itemRef.value, (el:UniElement|null) => {
if(el== null) return
resizeObserver.observe(el)
})
// onMounted(() => {
// nextTick(updateItemStyle)
// })
// #endif
onBeforeUnmount(() => {
manageChildInList?.(instance.proxy! as LPickerItemComponentPublicInstance, false)
// #ifdef APP-ANDROID
stop()
stopWatch()
resizeObserver.disconnect()
// #endif
})
// onMounted(()=>{
// if(props.options.length > 0 && curIndex.value == -1) {
// curIndex.value = 0
// }
// })
defineExpose({
setIndex,
setValue,
// setOptions,
// setUpdateItems,
getIndexByValue
})
</script>
<style lang="scss">
@import './index';
</style>

View File

@@ -0,0 +1,204 @@
<template>
<picker-view
class="l-picker-item__group"
:style="{opacity: options.length > 0 ? 1 : 0}"
:indicator-style="indicatorStyles"
:value="innerIndex"
@change="handlePick"
indicator-class="l-picker-item__indicator">
<picker-view-column class="l-picker-item__wrapper">
<text
class="l-picker-item__group-item"
v-for="(item, i) in options"
:style="[itemStyles, curIndex == i ? itemActiveStyles: {}]"
:class="{'l-picker-item__group-item--active': curIndex == i}"
:key="item.value">{{item.label}}</text>
</picker-view-column>
</picker-view>
</template>
<script lang="ts">
// @ts-nocheck
/**
* PickerItem 选择器子项组件
* @description 用于构建多列选择器的单个列项,通常作为 Picker 组件的子组件使用
* <br>插件类型LPickerItemComponentPublicInstance
* @tutorial https://ext.dcloud.net.cn/plugin?name=lime-picker
*
* @property {PickerColumnItem[]} options 当前列的选项列表(必填)
* @property {PickerValue} value 当前选中值
* @property {number} column 列索引标识从0开始计数
* @property {string | number} name 列名称标识符
*/
import { defineComponent, getCurrentInstance, inject, ref, computed, watch, onBeforeUnmount } from '@/uni_modules/lime-shared/vue';
import { unitConvert } from '@/uni_modules/lime-shared/unitConvert';
import { clamp } from '@/uni_modules/lime-shared/clamp'
import type { PickerItemProps, ManageChildInList, OnPick, UpdateItems } from './type';
import type { PickerColumnItem, PickerValue } from '../l-picker/type';
import pickerItemProps from './props';
export default defineComponent({
name: 'l-picker-item',
props: pickerItemProps,
setup(props, {expose}) {
const instance = getCurrentInstance()!;
const picker = inject<LPickerComponentPublicInstance|null>('limePicker', null);
const pickerItemInstanceArray = inject<Ref<LPickerItemComponentPublicInstance[]>|null>('limePickerItems', null);
const manageChildInList = inject<ManageChildInList|null>('limePickerManageChildInList', null);
manageChildInList?.(instance.proxy! as LPickerItemComponentPublicInstance , true)
const onPick = inject<OnPick|null>('limePickerOnPick', null);
const updateItems = inject<UpdateItems|null>('limePickerUpdateItems', null);
const curIndex = ref(-1)
const curValue = ref<PickerValue|null>(null);
const column = computed(() : number => props.column != -1 ? props.column : pickerItemInstanceArray?.value.indexOf(instance.proxy! as LPickerItemComponentPublicInstance) ?? props.column);
const elementPosition = computed(() : boolean[] => {
const totalElements = pickerItemInstanceArray?.value.length || 0;
return [column.value == 0, column.value == totalElements - 1]
});
const innerIndex = computed(():number[] => [curIndex.value])
const indicatorStyles = computed(() : string => {
const [isFirst, isLast] = elementPosition.value
let style = ``
if(isFirst) {
style+= 'border-top-left-radius:12rpx; border-bottom-left-radius:12rpx;'
}
if(isLast) {
style+= 'border-top-right-radius:12rpx; border-bottom-right-radius:12rpx;'
}
return `
${style}
height: ${picker?.itemHeight || '50px'};
background-color: rgba(0, 0, 0, 0.04); ${picker?.indicatorStyle}`
})
const itemStyles = computed(()=>{
const style:Record<string, any> = {};
if(picker?.itemColor) {
style['color'] = picker.itemColor!
}
if(picker?.itemFontSize) {
style['font-size'] = picker.itemFontSize!
}
return style
})
const itemActiveStyles = computed(() =>{
const style:Record<string, any> = {};
if(picker?.itemActiveColor) {
style['color'] = picker.itemActiveColor!
}
if (picker?.itemActiveFontWeight) {
style['font-weight'] = picker.itemActiveFontWeight!
}
return style
})
const getIndexByValue = (val: PickerValue | null) => {
let defaultIndex = 0;
if (val != null) {
defaultIndex = props.options.findIndex((item) => item.value == val);
}
return defaultIndex < 0 ? 0 : defaultIndex;
};
const setIndex = (index: number) =>{
let lastIndex = curIndex.value
let _index = clamp(index, 0, props.options.length - 1)
if(props.options.length > _index) {
curIndex.value = _index;
curValue.value = props.options[_index].value
}
// #ifdef WEB
if(lastIndex == _index || lastIndex == -1) return
if(instance.proxy!.$el) {
const childs = Array.from(instance.proxy!.$el.parentElement.children).slice(column.value + 1);
childs.forEach((child) => {
(child as HTMLElement).style.setProperty('--picker-duration', '300ms');
setTimeout(function() {
(child as HTMLElement).style.setProperty('--picker-duration', '0ms');
}, 299);
})
}
// #endif
}
const setValue = (value: PickerValue|null) =>{
if(value == curValue.value) return
curValue.value = value
const index = getIndexByValue(value)
setIndex(index)
}
const setOptions = () => {}
const setUpdateItems = () => {
const curItem = props.options.length > curIndex.value ? props.options[curIndex.value] : null;
if(curItem == null) return
updateItems?.(curItem, curIndex.value, column.value);
}
const handlePick = (e: UniPickerViewChangeEvent) => {
if(props.options.length == 0) return
const index = clamp(e.detail.value[0], 0, props.options.length - 1);
const curItem = props.options[index];
if(index == curIndex.value) return
setIndex(index)
onPick?.(curItem, index, column.value);
}
// const stop = watch(():PickerColumnItem[] => props.options, ()=> {
// if(JSON.stringify(o) == JSON.stringify(v)) return
// const index = (picker?.resetIndex || false) ? 0 : Math.max( Math.min(props.options.length - 1, curIndex.value), 0)
// const curItem = props.options[index];
// setIndex(index)
// setUpdateItems();
// // nextTick(()=>{
// // onPick?.(curItem, index, column.value);
// // })
// }) // ,{immediate: true}
const stopValue = watch(():PickerValue|null => props.value, (v : PickerValue|null)=>{
setValue(v);
setUpdateItems();
},{immediate: true})
onBeforeUnmount(()=>{
manageChildInList?.(instance.proxy! as LPickerItemComponentPublicInstance, false)
// stop()
stopValue()
})
// #ifdef VUE3
expose({
setIndex,
setValue,
// setOptions,
// setUpdateItems,
getIndexByValue
})
// #endif
return {
indicatorStyles,
innerIndex,
curIndex,
handlePick,
itemStyles,
itemActiveStyles,
// #ifdef VUE2
setIndex,
setValue,
getIndexByValue
// #endif
}
}
})
</script>
<style lang="scss">
@import './index';
</style>

View File

@@ -0,0 +1,15 @@
// @ts-nocheck
export default {
options: {
type: Array,
default: () => []
},
value: {
type: [String, Number],
default: null
},
column: {
type: Number,
default: -1
}
}

View File

@@ -0,0 +1,13 @@
// @ts-nocheck
import type{ PickerColumnItem, PickerValue } from '../l-picker/type';
export type ManageChildInList = (child: LPickerItemComponentPublicInstance, shouldAdd: boolean) => void;
export type OnPick = (value: PickerValue, index:number, column: number) => void;
export type UpdateItems = (value: PickerValue, index:number, column: number) => void;
export interface PickerItemProps {
options: PickerColumnItem[]
value?: PickerValue;
column: number
name?: string|number
}