diff --git a/packages-user/client-modules/src/render/components/page.tsx b/packages-user/client-modules/src/render/components/page.tsx index 35a0584..6857f13 100644 --- a/packages-user/client-modules/src/render/components/page.tsx +++ b/packages-user/client-modules/src/render/components/page.tsx @@ -20,6 +20,8 @@ export interface PageProps extends DefaultProps { pages: number; /** 页码组件的定位 */ loc: ElementLocator; + /** 当前页码 */ + page?: number; /** 页码的字体 */ font?: Font; /** 只有一页的时候,是否隐藏页码 */ @@ -28,6 +30,8 @@ export interface PageProps extends DefaultProps { export type PageEmits = { pageChange: (page: number) => void; + + 'update:page': (page: number) => void; }; export interface PageExpose { @@ -54,8 +58,8 @@ type PageSlots = SlotsType<{ }>; const pageProps = { - props: ['pages', 'loc', 'font', 'hideIfSingle'], - emits: ['pageChange'] + props: ['pages', 'loc', 'page', 'font', 'hideIfSingle'], + emits: ['pageChange', 'update:page'] } satisfies SetupComponentOptions< PageProps, PageEmits, @@ -85,7 +89,7 @@ export const Page = defineComponent< keyof PageEmits, PageSlots >((props, { slots, expose, emit }) => { - const nowPage = ref(0); + const nowPage = ref(props.page ?? 0); // 五个元素的位置 const leftLoc = ref([]); @@ -182,6 +186,7 @@ export const Page = defineComponent< if (nowPage.value !== target) { nowPage.value = target; emit('pageChange', target); + emit('update:page', target); } }; diff --git a/packages-user/client-modules/src/render/components/thumbnail.tsx b/packages-user/client-modules/src/render/components/thumbnail.tsx index e1bd37f..733dcb6 100644 --- a/packages-user/client-modules/src/render/components/thumbnail.tsx +++ b/packages-user/client-modules/src/render/components/thumbnail.tsx @@ -74,6 +74,6 @@ export const Thumbnail = defineComponent(props => { watch(props, update); return () => ( - + ); }, thumbnailProps); diff --git a/packages-user/client-modules/src/render/ui/save.tsx b/packages-user/client-modules/src/render/ui/save.tsx index 2cf7eb4..8770e5c 100644 --- a/packages-user/client-modules/src/render/ui/save.tsx +++ b/packages-user/client-modules/src/render/ui/save.tsx @@ -7,22 +7,29 @@ import { SetupComponentOptions, UIComponentProps } from '@motajs/system-ui'; -import { defineComponent, ref, computed, onMounted } from 'vue'; +import { + defineComponent, + ref, + computed, + onMounted, + shallowReactive +} from 'vue'; import { Page, PageExpose } from '../components'; import { useKey } from '../use'; -import { MAP_WIDTH, MAP_HEIGHT } from '../shared'; +import { MAP_WIDTH } from '../shared'; import { getSave, SaveData } from '../utils'; import { Thumbnail } from '../components/thumbnail'; +import { adjustGrid, IGridLayoutData } from '../utils/layout'; export interface SaveProps extends UIComponentProps, DefaultProps { loc: ElementLocator; } -export interface SaveBtnProps extends DefaultProps { +export interface SaveItemProps extends DefaultProps { loc: ElementLocator; index: number; - isSelected: boolean; - isDelete: boolean; + selected: boolean; + inDelete: boolean; data: SaveData | null; } @@ -35,26 +42,45 @@ export type SaveEmits = { exit: () => void; }; -export type SaveBtnEmits = { - /** 读取数据 */ - updateData: (isValid: boolean) => void; -}; - const saveProps = { props: ['loc', 'controller', 'instance'], emits: ['delete', 'emit', 'exit'] } satisfies SetupComponentOptions; const saveBtnProps = { - props: ['loc', 'index', 'isSelected', 'isDelete', 'data'] -} satisfies SetupComponentOptions; + props: ['loc', 'index', 'selected', 'inDelete', 'data'] +} satisfies SetupComponentOptions; -export const SaveBtn = defineComponent(props => { - const w = props.loc[2] ?? 200; +export const SaveItem = defineComponent(props => { const font = new Font('normal', 18); const statusFont = new Font('normal', 14); + + const w = computed(() => props.loc[2] ?? 200); + const lineWidth = computed(() => (props.selected ? 4 : 2)); + const imgLoc = computed(() => { + const size = w.value - 4; + return [2, 24, size, size]; + }); + + const name = computed(() => { + return props.index === -1 ? '自动存档' : `存档${props.index}`; + }); + const statusText = computed(() => { + if (!props.data) return ''; + else { + const hero = props.data.data.hero; + return `${hero.hp}/${hero.atk}/${hero.def}`; + } + }); + + const strokeStyle = computed(() => { + if (props.selected) return props.inDelete ? 'red' : 'gold'; + else return 'white'; + }); + + const floorId = computed(() => props.data?.data.floorId ?? 'empty'); const mapBlocks = computed(() => { - if (props.data === null || props.data === undefined) return void 0; + if (!props.data) return []; else { const currData = props.data.data; const map = core.maps.loadMap(currData.maps, currData.floorId); @@ -62,54 +88,42 @@ export const SaveBtn = defineComponent(props => { return map.blocks; } }); - const name = computed(() => - props.index === -1 ? '自动存档' : `存档${props.index + 1}` - ); - const statusText = computed(() => { - if (props.data === null || props.data === undefined) return ''; - else { - const hero = props.data.data.hero; - return `${hero.hp}/${hero.atk}/${hero.def}`; - } - }); - const strokeStyle = computed(() => { - if (props.isSelected) return props.isDelete ? 'red' : 'gold'; - else return 'white'; - }); - const lineWidth = computed(() => (props.isSelected ? 2 : 1)); return () => ( ); @@ -117,62 +131,108 @@ export const SaveBtn = defineComponent(props => { export const Save = defineComponent( (props, { emit }) => { - const row = 2; - const column = 3; - /** 除自动存档外,每一页容纳的存档数量 */ - const pageCap = row * column - 1; + const itemSize = 150; + const itemHeight = itemSize + 40; + const interval = 30; + const font = new Font('normal', 18); const pageFont = new Font('normal', 14); - const isDelete = ref(false); + /** 当前页上被选中的存档的posIndex */ + const selected = ref(0); + const now = ref(0); + const inDelete = ref(false); const pageRef = ref(); - /** posIndex 存档在当前页的序号 范围为0到pageCap-1 */ + const saveData: Record = shallowReactive({}); + + const width = computed(() => props.loc[2] ?? 200); + const height = computed(() => props.loc[3] ?? 200); + + const grid = computed(() => + adjustGrid( + width.value, + height.value - 30, + itemSize, + itemHeight, + interval + ) + ); + + const contentLoc = computed(() => { + const cx = width.value / 2; + const cy = (height.value - 30) / 2; + return [cx, cy, grid.value.width, grid.value.height, 0.5, 0.5]; + }); + + const deleteLoc = computed(() => { + const pad = (width.value - grid.value.width) / 2; + return [pad, height.value - 13, void 0, void 0, 0, 1]; + }); + + const exitLoc = computed(() => { + const pad = (width.value - grid.value.width) / 2; + const right = width.value - pad; + return [right, height.value - 13, void 0, void 0, 1, 1]; + }); + + /** + * 获取存档在当前页的序号,范围为 0 到 pageCap-1。 + */ const getPosIndex = (index: number) => { if (index === -1) return 0; - return index - pageCap * (pageRef.value?.now() || 0) + 1; - }; - /** index 存档的总序号 从0开始 用于数据交互 */ - const getIndex = (posIndex: number, page: number) => { - return page * pageCap + posIndex - 1; + return index % (grid.value.count - 1); }; - /** 存档数据的列表 */ - const dataList = ref<(SaveData | null)[]>( - Array(pageCap + 1).fill(null) - ); - const updateDataList = (page: number) => { - dataList.value.forEach((_ele, i) => { - getSave(getIndex(i, page)).then(saveValue => { - dataList.value[i] = saveValue; - }); + /** + * 获取存档的总序号,从 0 开始,用于数据交互。 + */ + const getIndex = (posIndex: number, page: number) => { + return page * grid.value.count + posIndex - 1; + }; + + const updateDataList = async (page: number) => { + const promises: Promise[] = []; + for (let i = 0; i < grid.value.count; i++) { + const index = getIndex(i, page); + promises.push(getSave(index)); + } + const data = await Promise.all(promises); + + data.forEach((v, i) => { + if (v) { + saveData[i] = v; + } else { + saveData[i] = null; + } }); }; - const hasData = (posIndex: number) => { - return dataList.value[posIndex] !== null; + + const exist = (index: number) => { + return saveData[index] !== null; }; - const getData = (posIndex: number) => dataList.value[posIndex]; - const deleteData = (posIndex: number) => { - dataList.value[posIndex] = null; + + const deleteData = (index: number) => { + saveData[index] = null; }; onMounted(() => { - const currPage = pageRef.value?.now() || 0; - updateDataList(currPage); + updateDataList(now.value); }); - /** 当前页上被选中的存档的posIndex */ - const pickIndex = ref(1); - const emitSave = (index: number) => { const posIndex = getPosIndex(index); - if (isDelete.value) { - emit('delete', index, hasData(posIndex)); + if (inDelete.value) { + emit('delete', index, exist(posIndex)); deleteData(posIndex); } else { - emit('emit', index, hasData(posIndex)); + emit('emit', index, exist(posIndex)); + } + if (index === -1) { + selected.value = 0; + } else { + selected.value = (index % (grid.value.count - 1)) + 1; } - pickIndex.value = (index % pageCap) + 1; }; const wheel = (ev: IWheelEvent) => { @@ -185,7 +245,7 @@ export const Save = defineComponent( }; const toggleDelete = () => { - isDelete.value = !isDelete.value; + inDelete.value = !inDelete.value; }; const exit = () => { @@ -194,11 +254,14 @@ export const Save = defineComponent( }; // #region 按键实现 + const [key] = useKey(); key.realize('confirm', () => { - const currPage = pageRef.value?.now(); - if (currPage === void 0) return; - emitSave(pageCap * currPage + pickIndex.value); + if (selected.value === 0) { + emitSave(-1); + } else { + emitSave((grid.value.count - 1) * now.value + selected.value); + } }) .realize('exit', exit) .realize('@save_exit', exit) @@ -220,14 +283,16 @@ export const Save = defineComponent( '@save_up', () => { if (!pageRef.value) return; - const now = pageRef.value.now(); - if (pickIndex.value >= row) { - pickIndex.value -= column; + const cols = grid.value.cols; + const count = grid.value.count; + if (selected.value >= cols) { + selected.value -= cols; } else { - if (now === 0) { - pickIndex.value = 0; + if (now.value === 0) { + selected.value = 0; } else { - pickIndex.value += pageCap + 1 - column; + const selectedCol = selected.value % cols; + selected.value = count - (cols - selectedCol); pageRef.value?.movePage(-1); } } @@ -237,10 +302,13 @@ export const Save = defineComponent( .realize( '@save_down', () => { - if (pickIndex.value <= pageCap - row) { - pickIndex.value += column; + const cols = grid.value.cols; + const count = grid.value.count; + if (selected.value < count - cols) { + selected.value += cols; } else { - pickIndex.value += column - pageCap - 1; + const selectedCol = selected.value % cols; + selected.value = selectedCol; pageRef.value?.movePage(1); } }, @@ -250,12 +318,12 @@ export const Save = defineComponent( '@save_left', () => { if (!pageRef.value) return; - const now = pageRef.value.now(); - if (pickIndex.value > 0) { - pickIndex.value--; + const count = grid.value.count; + if (selected.value > 0) { + selected.value--; } else { - if (now > 0) { - pickIndex.value = pageCap; + if (now.value > 0) { + selected.value = count; pageRef.value?.movePage(-1); } } @@ -265,99 +333,62 @@ export const Save = defineComponent( .realize( '@save_right', () => { - if (pickIndex.value < pageCap) { - pickIndex.value++; + const count = grid.value.count; + if (selected.value < count) { + selected.value++; } else { - pickIndex.value = 0; + selected.value = 0; pageRef.value?.movePage(1); } }, { type: 'down-repeat' } ); - // #endregion return () => ( {(page: number) => ( - - emitSave(-1)} - cursor="pointer" - data={getData(0)} - /> - emitSave(page * pageCap)} - cursor="pointer" - data={getData(1)} - /> - emitSave(page * pageCap + 1)} - cursor="pointer" - data={getData(2)} - /> - emitSave(page * pageCap + 2)} - cursor="pointer" - data={getData(3)} - /> - emitSave(page * pageCap + 3)} - cursor="pointer" - data={getData(4)} - /> - emitSave(page * pageCap + 4)} - cursor="pointer" - data={getData(5)} - /> + + {grid.value.locs.map((v, i) => { + const count = grid.value.count; + const rawIndex = (count - 1) * page + i; + const index = i === 0 ? -1 : rawIndex; + return ( + emitSave(index)} + onEnter={() => (selected.value = i)} + /> + ); + })} )} ; +}; /** * 深度只读一个对象,使其所有属性都只读