From 2d4a6ebe75599eaa51d5fb0f522dc9fa6825af00 Mon Sep 17 00:00:00 2001 From: wupengfei <834520024@qq.com> Date: 星期三, 12 二月 2025 14:58:29 +0800 Subject: [PATCH] feat: mine --- apps/cMiniApp/src/components/Portal/portal-host.vue | 104 ++++++ apps/cMiniApp/src/components/Portal/PortalManager.vue | 44 ++ apps/cMiniApp/src/assets/mine/icon-collect.png | 0 apps/cMiniApp/src/subpackages/mine/editMineInfo/InnerPage.vue | 65 ++++ apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.config.ts | 3 apps/cMiniApp/src/components/Input/input.ts | 31 ++ apps/cMiniApp/src/components/Input/ChooseInput.vue | 37 ++ apps/cMiniApp/src/components/Portal/Portal.vue | 19 + apps/cMiniApp/src/assets/mine/icon-agreement.png | 0 apps/cMiniApp/src/components/Input/ChooseInputWithAreaPicker.vue | 76 +++++ apps/cMiniApp/src/assets/mine/icon-recruit.png | 0 apps/cMiniApp/src/components/Portal/portal-container.vue | 50 +++ apps/cMiniApp/src/components/Portal/portal-consumer.vue | 37 ++ apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.vue | 17 + apps/cMiniApp/src/subpackages/mine/editMineInfo/constants/index.ts | 19 + apps/cMiniApp/src/constants/router.ts | 1 apps/cMiniApp/src/app.config.ts | 1 apps/cMiniApp/src/components/Input/NumberInput.vue | 55 +++ apps/cMiniApp/src/components/Portal/index.ts | 12 apps/cMiniApp/src/components/Portal/portal.ts | 72 ++++ apps/cMiniApp/src/subpackages/mine/mineCurriculumVitae/InnerPage.vue | 139 ++++++++ apps/cMiniApp/src/pages/mine/index.vue | 16 apps/cMiniApp/src/components/Input/ChooseInputWithPicker.vue | 73 ++++ 23 files changed, 857 insertions(+), 14 deletions(-) diff --git a/apps/cMiniApp/src/app.config.ts b/apps/cMiniApp/src/app.config.ts index 72d0941..2816e7a 100644 --- a/apps/cMiniApp/src/app.config.ts +++ b/apps/cMiniApp/src/app.config.ts @@ -80,6 +80,7 @@ 'mineAgreementSign/mineAgreementSign', 'mineAgreementSignDetail/mineAgreementSignDetail', 'mineCurriculumVitae/mineCurriculumVitae', + 'editMineInfo/editMineInfo', 'setting/setting', ], }, diff --git a/apps/cMiniApp/src/assets/mine/icon-agreement.png b/apps/cMiniApp/src/assets/mine/icon-agreement.png new file mode 100644 index 0000000..1cd2914 --- /dev/null +++ b/apps/cMiniApp/src/assets/mine/icon-agreement.png Binary files differ diff --git a/apps/cMiniApp/src/assets/mine/icon-collect.png b/apps/cMiniApp/src/assets/mine/icon-collect.png new file mode 100644 index 0000000..7f3b0e3 --- /dev/null +++ b/apps/cMiniApp/src/assets/mine/icon-collect.png Binary files differ diff --git a/apps/cMiniApp/src/assets/mine/icon-recruit.png b/apps/cMiniApp/src/assets/mine/icon-recruit.png new file mode 100644 index 0000000..98107c1 --- /dev/null +++ b/apps/cMiniApp/src/assets/mine/icon-recruit.png Binary files differ diff --git a/apps/cMiniApp/src/components/Input/ChooseInput.vue b/apps/cMiniApp/src/components/Input/ChooseInput.vue new file mode 100644 index 0000000..6486c46 --- /dev/null +++ b/apps/cMiniApp/src/components/Input/ChooseInput.vue @@ -0,0 +1,37 @@ +<template> + <nut-input + class="nut-input-text bole-input-text" + type="text" + readonly + alwaysEmbed + v-bind="$attrs" + > + <template #clear> + <slot name="clear"></slot> + </template> + <template #right> + <slot name="right"> + <RectRight :size="12" class="common-choose-input-icon" /> + </slot> + </template> + </nut-input> +</template> + +<script setup lang="ts"> +import { RectRight } from '@nutui/icons-vue-taro'; + +defineOptions({ + name: 'ChooseInput', +}); +</script> + +<style lang="scss"> +@import '@/styles/common.scss'; + +.common-choose-input-icon { + // width: 13px; + // height: 23px; + margin-left: 18px; + color: boleGetCssVar('text-color', 'primary'); +} +</style> diff --git a/apps/cMiniApp/src/components/Input/ChooseInputWithAreaPicker.vue b/apps/cMiniApp/src/components/Input/ChooseInputWithAreaPicker.vue new file mode 100644 index 0000000..b7eaec8 --- /dev/null +++ b/apps/cMiniApp/src/components/Input/ChooseInputWithAreaPicker.vue @@ -0,0 +1,76 @@ +<template> + <ChooseInput :modelValue="inputValue" @click="handleOpen()"></ChooseInput> +</template> + +<script setup lang="ts"> +import { useAllAreaList } from '@/hooks'; +import Portal from '../Portal'; +import ChooseInput from './ChooseInput.vue'; +import { Popup, Picker } from '@nutui/nutui-taro'; + +defineOptions({ + name: 'ChooseInputWithAreaPicker', +}); + +const { findAreaNameFromCode } = useAllAreaList(); + +type Props = { + fieldNames?: object; + columns: API.AreaTreeNode[]; + modelValue: Array<string | number>; + title?: string; +}; + +const props = withDefaults(defineProps<Props>(), { + title: '閫夋嫨鍦板潃', + fieldNames: () => ({ + text: 'areaName', + value: 'areaCode', + children: 'children', + }), +}); +const inputValue = computed(() => + props.modelValue.map((x) => findAreaNameFromCode(Number(x))).join(',') +); + +const emit = defineEmits<{ + (e: 'update:modelValue', val: Array<string | number>): void; +}>(); + +function handleOpen() { + Portal.add((key) => { + return h( + Portal.Container, + { keyNumber: key, delayOpen: true }, + { + default: ({ open, onClose }) => + h( + Popup, + { + visible: open.value, + 'onUpdate:visible': (value) => !value && onClose(), + position: 'bottom', + }, + { + default: () => + h(Picker, { + modelValue: props.modelValue, + columns: props.columns, + fieldNames: props.fieldNames, + title: props.title, + onCancel: onClose, + onConfirm: ({ selectedValue, selectedOptions }) => { + emit( + 'update:modelValue', + selectedOptions.map((x) => x.areaCode) + ); + onClose(); + }, + }), + } + ), + } + ); + }); +} +</script> diff --git a/apps/cMiniApp/src/components/Input/ChooseInputWithPicker.vue b/apps/cMiniApp/src/components/Input/ChooseInputWithPicker.vue new file mode 100644 index 0000000..dacca73 --- /dev/null +++ b/apps/cMiniApp/src/components/Input/ChooseInputWithPicker.vue @@ -0,0 +1,73 @@ +<template> + <ChooseInput :modelValue="inputValue" @click="handleOpen()"></ChooseInput> +</template> + +<script setup lang="ts"> +import Portal from '../Portal'; +import ChooseInput from './ChooseInput.vue'; +import { Popup, Picker } from '@nutui/nutui-taro'; +import { convertOptions, ValueEnum } from './input'; + +defineOptions({ + name: 'ChooseInputWithPicker', +}); + +type Props = { + enumLabelKey?: string; + enumValueKey?: string; + valueEnum?: ValueEnum; + modelValue: string | number; +}; + +const props = withDefaults(defineProps<Props>(), { + enumLabelKey: 'name', + enumValueKey: 'id', +}); + +const emit = defineEmits<{ + (e: 'update:modelValue', val: string | number): void; +}>(); + +const options = computed(() => + convertOptions(props.valueEnum, props.enumLabelKey, props.enumValueKey) +); + +const inputValue = computed( + () => options.value?.find((x) => x.value === props.modelValue)?.text ?? '' +); + +function handleOpen() { + console.log('handleOpen: '); + const _modelValue = [props.modelValue]; + Portal.add((key) => { + return h( + Portal.Container, + { keyNumber: key, delayOpen: true }, + { + default: ({ open, onClose }) => + h( + Popup, + { + visible: open.value, + 'onUpdate:visible': (value) => !value && onClose(), + position: 'bottom', + }, + { + default: () => + h(Picker, { + modelValue: _modelValue, + columns: options.value, + onCancel: onClose, + onConfirm: ({ selectedValue, selectedOptions }) => { + console.log('selectedValue: ', selectedValue, selectedOptions); + emit('update:modelValue', selectedOptions[0].value); + onClose(); + }, + }), + } + ), + } + ); + }); +} +</script> diff --git a/apps/cMiniApp/src/components/Input/NumberInput.vue b/apps/cMiniApp/src/components/Input/NumberInput.vue new file mode 100644 index 0000000..05ba733 --- /dev/null +++ b/apps/cMiniApp/src/components/Input/NumberInput.vue @@ -0,0 +1,55 @@ +<template> + <nut-input type="number" :formatter="formatter" formatTrigger="onBlur"> + <template #right> + <slot name="right"></slot> + </template> + </nut-input> +</template> + +<script setup lang="ts"> +defineOptions({ + name: 'NumberInput', +}); + +type Props = { + min?: number; + max?: number; + precision?: number; +}; + +const props = withDefaults(defineProps<Props>(), { + max: Math.pow(2, 53) - 1, +}); + +function formatter(value: string): string { + const newVal = value !== '' ? Number.parseFloat(value) : ''; + if (Number.isNaN(newVal)) { + return ''; + } + if (newVal && newVal > props.max) { + return `${toPrecision(props.max)}`; + } + if (props.min !== undefined && newVal && newVal < props.min) { + return `${toPrecision(props.min)}`; + } + return newVal !== '' ? `${toPrecision(newVal)}` : newVal; +} + +function toPrecision(num: number) { + if (props.precision) { + if (props.precision === 0) return Math.round(num); + let snum = String(num); + const pointPos = snum.indexOf('.'); + if (pointPos === -1) return num; + const nums = snum.replace('.', '').split(''); + const datum = nums[pointPos + props.precision]; + if (!datum) return num; + const length = snum.length; + if (snum.charAt(length - 1) === '5') { + snum = `${snum.slice(0, Math.max(0, length - 1))}6`; + } + return Number(snum).toFixed(props.precision); + } + return String(num); +} +</script> diff --git a/apps/cMiniApp/src/components/Input/input.ts b/apps/cMiniApp/src/components/Input/input.ts new file mode 100644 index 0000000..d1a5309 --- /dev/null +++ b/apps/cMiniApp/src/components/Input/input.ts @@ -0,0 +1,31 @@ +import _ from 'lodash'; + +export type ValueEnumItem = { [key: string]: any }; +export type ValueEnum = ValueEnumItem[] | Record<string | number, string>; +export type OptionItem = { + text: string; + value: string | number; + [key: string]: any; +}; + +export function convertOptions( + valueEnum: ValueEnum, + enumLabelKey: string, + enumValueKey: string +): OptionItem[] { + return _.isArray(valueEnum) + ? valueEnum.map((x) => ({ + ...x, + text: x[enumLabelKey], + value: _.isNaN(Number(x[enumValueKey])) ? x[enumValueKey] : Number(x[enumValueKey]), + })) + : Object.keys(valueEnum).map((x) => ({ + value: _.isNaN(Number(x)) ? x : Number(x), + text: valueEnum[x], + })); +} + +export type ChooseCheckBoxOptionItem = { + text: string; + value: string | number; +}; diff --git a/apps/cMiniApp/src/components/Portal/Portal.vue b/apps/cMiniApp/src/components/Portal/Portal.vue new file mode 100644 index 0000000..06d5c1a --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/Portal.vue @@ -0,0 +1,19 @@ +<template> + <PortalConsumer :manager="portalContext"> + <template #default> + <slot /> + </template> + </PortalConsumer> +</template> + +<script setup lang="ts"> +import PortalConsumer from './portal-consumer.vue'; +// import PortalContainer from './portal-container'; +import { portal, usePortalContext } from './portal'; + +defineOptions({ + name: 'Portal', +}); + +const portalContext = usePortalContext(); +</script> diff --git a/apps/cMiniApp/src/components/Portal/PortalManager.vue b/apps/cMiniApp/src/components/Portal/PortalManager.vue new file mode 100644 index 0000000..4f0a6cd --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/PortalManager.vue @@ -0,0 +1,44 @@ +<script lang="ts"> +import { State, PortalNode } from './portal'; + +export default defineComponent({ + name: 'PortalManager', + setup(props, { expose }) { + const state = reactive<State>({ + portals: [], + }); + + const mount = (key: number, children: PortalNode) => { + state.portals.push({ key, children }); + }; + const update = (key: number, children: PortalNode) => { + state.portals = state.portals.map((item) => { + if (item.key === key) { + return { ...item, children }; + } + return item; + }); + }; + + const unmount = (key: number) => { + state.portals = state.portals.filter((item) => item.key !== key); + }; + + expose({ + mount, + update, + unmount, + }); + + return () => { + return h( + 'div', + null, + state.portals.map((item) => { + return h('div', { key: item.key }, [item.children]); + }) + ); + }; + }, +}); +</script> diff --git a/apps/cMiniApp/src/components/Portal/index.ts b/apps/cMiniApp/src/components/Portal/index.ts new file mode 100644 index 0000000..29fbcf8 --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/index.ts @@ -0,0 +1,12 @@ +import PortalContainer from './portal-container.vue'; +import PortalHost from './portal-host.vue'; +import { portal } from './portal'; +import Portal from './Portal.vue'; + +export default { + Host: PortalHost, + add: portal.add, + remove: portal.remove, + Portal: Portal, + Container: PortalContainer, +}; diff --git a/apps/cMiniApp/src/components/Portal/portal-consumer.vue b/apps/cMiniApp/src/components/Portal/portal-consumer.vue new file mode 100644 index 0000000..ba1a582 --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/portal-consumer.vue @@ -0,0 +1,37 @@ +<script lang="ts"> +import { PortalMethods } from './portal'; + +export default defineComponent({ + name: 'PortalConsumer', + props: { + manager: { + type: Object as PropType<PortalMethods>, + }, + }, + setup(props) { + const _key = ref<number>(); + + const slots = useSlots(); + + onMounted(() => { + if (!props.manager) { + throw new Error('forgot'); + } + const defaultSlot = slots.default(); + props.manager.update(_key.value, defaultSlot); + _key.value = props.manager.mount(defaultSlot); + }); + + onUpdated(() => { + const defaultSlot = slots.default(); + props.manager.update(_key.value, defaultSlot); + }); + + onUnmounted(() => { + props.manager.unmount(_key.value); + }); + + return () => null; + }, +}); +</script> diff --git a/apps/cMiniApp/src/components/Portal/portal-container.vue b/apps/cMiniApp/src/components/Portal/portal-container.vue new file mode 100644 index 0000000..7c12a7e --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/portal-container.vue @@ -0,0 +1,50 @@ +<script lang="ts"> +import { VNode } from 'vue'; +import { portal } from './portal'; + +export default defineComponent({ + name: 'portal-container', + props: { + render: { + type: Function as PropType<(open: Ref<boolean>, onClose?: () => any) => VNode>, + }, + keyNumber: { + type: Number, + }, + /** + * 鏄惁寤惰繜璁剧疆open涓簍rue + */ + delayOpen: { + type: Boolean, + }, + }, + setup(props, { slots }) { + const open = ref(!props.delayOpen); + + function onClose() { + open.value = false; + } + + onMounted(() => { + if (props.delayOpen) { + setTimeout(() => { + open.value = true; + }, 30); + } + }); + + watch(open, (open, preOpen) => { + if (preOpen && !open) { + setTimeout(() => { + portal.remove(props.keyNumber); + }, 300); + } + }); + + return () => { + // const childrenNode = props.render(open, onClose); + return slots.default?.({ open, onClose }); + }; + }, +}); +</script> diff --git a/apps/cMiniApp/src/components/Portal/portal-host.vue b/apps/cMiniApp/src/components/Portal/portal-host.vue new file mode 100644 index 0000000..05068a7 --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/portal-host.vue @@ -0,0 +1,104 @@ +<template> + <slot></slot> + <PortalManager ref="_manager" /> +</template> + +<script lang="ts"> +defineComponent({ + name: 'portal-host', + inheritAttrs: false, +}); +</script> + +<script setup lang="ts"> +import { + PortalContextKey, + Operation, + getUniqueKey, + addType, + removeType, + TopViewEventEmitter, + PortalNode, + PortalManagerInstance, +} from './portal'; +import PortalManager from './PortalManager.vue'; + +const _nextKey = ref(0); +const _queue = ref<Operation[]>([]); +const _manager = ref<PortalManagerInstance>(); + +onMounted(() => { + TopViewEventEmitter.on(getUniqueKey(addType), _mount); + TopViewEventEmitter.on(getUniqueKey(removeType), _unmount); + + while (_queue.value.length && _manager.value) { + const action = _queue.value.pop(); + if (!action) { + continue; + } + + switch (action.type) { + case 'mount': + _manager.value.mount(action.key, action.children); + break; + case 'update': + _manager.value.update(action.key, action.children); + break; + case 'unmount': + _manager.value.unmount(action.key); + break; + } + } +}); + +onUnmounted(() => { + TopViewEventEmitter.off(getUniqueKey(addType), _mount); + TopViewEventEmitter.off(getUniqueKey(removeType), _unmount); +}); + +const _setManager = (manager?: any) => { + _manager.value = manager; +}; + +const _mount = (children: PortalNode, _key?: number) => { + const key = _key || _nextKey.value++; + if (_manager.value) { + _manager.value.mount(key, children); + } else { + _queue.value.push({ type: 'mount', key, children }); + } + + return key; +}; + +const _update = (key: number, children: PortalNode) => { + if (_manager.value) { + _manager.value.update(key, children); + } else { + const op: Operation = { type: 'mount', key, children }; + const index = _queue.value.findIndex( + (o) => o.type === 'mount' || (o.type === 'update' && o.key === key) + ); + + if (index > -1) { + _queue.value[index] = op; + } else { + _queue.value.push(op); + } + } +}; + +const _unmount = (key: number) => { + if (_manager.value) { + _manager.value.unmount(key); + } else { + _queue.value.push({ type: 'unmount', key }); + } +}; + +provide(PortalContextKey, { + mount: _mount, + update: _update, + unmount: _unmount, +}); +</script> diff --git a/apps/cMiniApp/src/components/Portal/portal.ts b/apps/cMiniApp/src/components/Portal/portal.ts new file mode 100644 index 0000000..38b8216 --- /dev/null +++ b/apps/cMiniApp/src/components/Portal/portal.ts @@ -0,0 +1,72 @@ +import type { VNode } from 'vue'; +import Taro from '@tarojs/taro'; + +export type PortalNode = VNode | VNode[]; + +export type State = { + portals: Array<{ + key: number; + children: PortalNode; + }>; +}; +export type PortalManagerState = { + portals: Array<{ + key: number; + children: PortalNode; + }>; +}; + +export type PortalMethods = { + mount: (children: PortalNode) => number; + update: (key: number, children: PortalNode) => void; + unmount: (key: number) => void; +}; + +export type Operation = + | { type: 'mount'; key: number; children: PortalNode } + | { type: 'update'; key: number; children: PortalNode } + | { type: 'unmount'; key: number }; + +export const PortalContextKey: InjectionKey<PortalMethods> = Symbol('PortalContextKey'); + +export function usePortalContext() { + return inject(PortalContextKey); +} + +export function getUniqueKey(key: string) { + const router = Taro.getCurrentInstance().router; + const prefix = router.path; + return `${prefix}_${key}`; +} + +// events +export const addType = 'ADD_PORTAL'; +export const removeType = 'REMOVE_PORTAL'; + +export const TopViewEventEmitter = new Taro.Events(); + +class PortalGuard { + private nextKey = 10000; + add = (render: (_key: number) => PortalNode) => { + const key = this.nextKey++; + const node = render(key); + TopViewEventEmitter.trigger(getUniqueKey(addType), node, key); + return key; + }; + remove = (key: number) => { + TopViewEventEmitter.trigger(getUniqueKey(removeType), key); + }; +} +/** + * portal + */ +export const portal = new PortalGuard(); + +export type PortalManagerInstance = { + mount: (key: number, children: PortalNode) => void; + update: (key: number, children: PortalNode) => void; + unmount: (key: number) => { + key: number; + children: PortalNode; + }[]; +}; diff --git a/apps/cMiniApp/src/constants/router.ts b/apps/cMiniApp/src/constants/router.ts index 98d8b95..083e742 100644 --- a/apps/cMiniApp/src/constants/router.ts +++ b/apps/cMiniApp/src/constants/router.ts @@ -33,5 +33,6 @@ mineAgreementSign = '/subpackages/mine/mineAgreementSign/mineAgreementSign', mineAgreementSignDetail = '/subpackages/mine/mineAgreementSignDetail/mineAgreementSignDetail', mineCurriculumVitae = '/subpackages/mine/mineCurriculumVitae/mineCurriculumVitae', + editMineInfo = '/subpackages/mine/editMineInfo/editMineInfo', setting = '/subpackages/mine/setting/setting', } diff --git a/apps/cMiniApp/src/pages/mine/index.vue b/apps/cMiniApp/src/pages/mine/index.vue index 5e04d6a..e7ecf54 100644 --- a/apps/cMiniApp/src/pages/mine/index.vue +++ b/apps/cMiniApp/src/pages/mine/index.vue @@ -75,10 +75,10 @@ </div> </List> <List class="mine-list-wrapper mine-setting-list"> - <ListItem :icon="IconSetting" title="鎴戞敹钘忕殑浠诲姟" @click="goMineCollectTask"></ListItem> - <ListItem :icon="IconSetting" title="鍗忚绛剧害" @click="goMineAgreementSign"></ListItem> + <ListItem :icon="IconCollect" title="鎴戞敹钘忕殑浠诲姟" @click="goMineCollectTask"></ListItem> + <ListItem :icon="IconAgreement" title="鍗忚绛剧害" @click="goMineAgreementSign"></ListItem> <ListItem :icon="IconSetting" title="璁剧疆" @click="goSetting"></ListItem> - <ListItem :icon="IconSetting" title="鎴戣鎷涗汉/鐢ㄤ汉" @click="goSetting"></ListItem> + <ListItem :icon="IconRecruit" title="鎴戣鎷涗汉/鐢ㄤ汉" @click="goSetting"></ListItem> </List> </ContentScrollView> </PageLayoutWithBg> @@ -88,6 +88,9 @@ import { TransparentNavigationBar, ContentScrollView, UserHomeTopView } from '@/components'; import IconArrow from '@/assets/setting/icon-arrow.png'; import IconSetting from '@/assets/mine/icon-setting.png'; +import IconCollect from '@/assets/mine/icon-collect.png'; +import IconAgreement from '@/assets/mine/icon-agreement.png'; +import IconRecruit from '@/assets/mine/icon-recruit.png'; import IconOrderSign from '@/assets/mine/icon-order-sign.png'; import IconOrderHire from '@/assets/mine/icon-order-hire.png'; import IconOrderCancel from '@/assets/mine/icon-order-cancel.png'; @@ -162,4 +165,11 @@ .mine-setting-badge { margin-right: 20px; } + +.mine-setting-list { + .pro-list-item-icon { + width: 48px; + height: 48px; + } +} </style> diff --git a/apps/cMiniApp/src/subpackages/mine/editMineInfo/InnerPage.vue b/apps/cMiniApp/src/subpackages/mine/editMineInfo/InnerPage.vue new file mode 100644 index 0000000..b3e507b --- /dev/null +++ b/apps/cMiniApp/src/subpackages/mine/editMineInfo/InnerPage.vue @@ -0,0 +1,65 @@ +<template> + <ContentScrollView :paddingH="false"> + <nut-form :model-value="form" ref="formRef" :rules="rules"> + <nut-form-item label="濮撳悕:" prop="name"> + <nut-input v-model.trim="form.name" placeholder="璇疯緭鍏ヤ紒涓氬悕绉�" /> + </nut-form-item> + <nut-form-item label="鎵嬫満鍙�:" prop="phone" required> + <nut-input v-model.trim="form.phone" placeholder="璇疯緭鍏ユ墜鏈哄彿" type="text" /> + </nut-form-item> + <nut-form-item label="韬唤:" class="bole-form-item" prop="gender"> + <ChooseInputWithPicker + v-model="form.gender" + placeholder="璇烽�夋嫨韬唤" + :value-enum="MineHireTypeText" + /> + </nut-form-item> + </nut-form> + </ContentScrollView> + <PageFooter> + <PageFooterBtn type="primary" @click="handleConfirm">淇濆瓨</PageFooterBtn> + </PageFooter> +</template> + +<script setup lang="ts"> +import { useUserStore } from '@/stores/modules/user'; +import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types'; +import ChooseInputWithPicker from '@/components/Input/ChooseInputWithPicker.vue'; +import { MineHireTypeText, MineHireType } from './constants'; + +defineOptions({ + name: 'InnerPage', +}); + +const userStore = useUserStore(); + +const form = reactive({ + name: '', + phone: '', + gender: MineHireType.All, +}); + +const rules = reactive<FormRules>({ + phone: [{ required: true, message: '璇疯緭鍏ユ墜鏈哄彿' }], +}); +const formRef = ref<any>(null); +function handleConfirm() { + if (!formRef.value) return; + formRef.value.validate().then(({ valid, errors }: any) => { + if (valid) { + confirm(); + } + }); +} + +function confirm() {} +</script> + +<style lang="scss"> +@import '@/styles/common.scss'; + +.task-card-actions-text { + font-size: 24px; + line-height: 42px; +} +</style> diff --git a/apps/cMiniApp/src/subpackages/mine/editMineInfo/constants/index.ts b/apps/cMiniApp/src/subpackages/mine/editMineInfo/constants/index.ts new file mode 100644 index 0000000..c3d377a --- /dev/null +++ b/apps/cMiniApp/src/subpackages/mine/editMineInfo/constants/index.ts @@ -0,0 +1,19 @@ +export enum MineHireType { + All = 0, + InProgress = 10, + WaitCheck = 20, + Finished = 30, +} + +export const MineHireTypeText = { + [MineHireType.All]: '鍏ㄩ儴', + [MineHireType.InProgress]: '杩涜涓�', + [MineHireType.WaitCheck]: '寰呴獙鏀�', + [MineHireType.Finished]: '宸插畬鎴�', +}; + +export const MineHireTypeColor = { + [MineHireType.InProgress]: '#3A71FF', + [MineHireType.WaitCheck]: '#FF7D00', + [MineHireType.Finished]: '#9FA4AC', +}; diff --git a/apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.config.ts b/apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.config.ts new file mode 100644 index 0000000..305fdb1 --- /dev/null +++ b/apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.config.ts @@ -0,0 +1,3 @@ +export default definePageConfig({ + disableScroll: true, +}); diff --git a/apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.vue b/apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.vue new file mode 100644 index 0000000..8485302 --- /dev/null +++ b/apps/cMiniApp/src/subpackages/mine/editMineInfo/editMineInfo.vue @@ -0,0 +1,17 @@ +<template> + <PageLayout class="index-page-wrapper" :title="'缂栬緫涓汉淇℃伅'"> + <InnerPage></InnerPage> + </PageLayout> +</template> + +<script setup lang="ts"> +import InnerPage from './InnerPage.vue'; + +defineOptions({ + name: 'editMineInfo', +}); +</script> + +<style lang="scss"> +@import '@/styles/common.scss'; +</style> diff --git a/apps/cMiniApp/src/subpackages/mine/mineCurriculumVitae/InnerPage.vue b/apps/cMiniApp/src/subpackages/mine/mineCurriculumVitae/InnerPage.vue index 61d5f17..f0d25e7 100644 --- a/apps/cMiniApp/src/subpackages/mine/mineCurriculumVitae/InnerPage.vue +++ b/apps/cMiniApp/src/subpackages/mine/mineCurriculumVitae/InnerPage.vue @@ -19,7 +19,7 @@ <img :src="IconAuth" class="mine-curriculum-info-item-gender-icon" /> </div> </div> - <IconFont name="rect-right" size="16" color="#6D6E6E"></IconFont> + <IconFont name="rect-right" size="16" color="#6D6E6E" @click="goEditMineInfo"></IconFont> </div> <div class="mine-curriculum-info-item"> <div class="mine-curriculum-info-item-left"> @@ -35,28 +35,64 @@ </div> </div> <List class="mine-curriculum-intention"> - <div class="mine-curriculum-intention-title"> - <div class="mine-curriculum-intention-title-text">姹傝亴鎰忓悜</div> - <div class="mine-curriculum-intention-title-edit"> - 缂栬緫 - <img :src="IconArrow" class="" /> + <div class="mine-curriculum-intention-content"> + <div class="mine-curriculum-intention-title"> + <div class="mine-curriculum-intention-title-text">姹傝亴鎰忓悜</div> + <div class="mine-curriculum-intention-title-edit"> + 缂栬緫 + <img :src="IconArrow" class="mine-curriculum-intention-title-edit-icon" /> + </div> </div> + <MineAgreementSignDetailItem label="鏈熸湜宀椾綅" class="mine-curriculum-intention-job"> + <template #detail> + <div class="mine-curriculum-intention-job-content"> + <div class="mine-curriculum-intention-job-item">瀹㈡埧鏈嶅姟鍛�</div> + <div class="mine-curriculum-intention-job-item">瀹㈡埧鏈嶅姟鍛�</div> + <div class="mine-curriculum-intention-job-item">瀹㈡埧鏈嶅姟鍛�</div> + <div class="mine-curriculum-intention-job-item">瀹㈡埧鏈嶅姟鍛�</div> + </div> + </template> + </MineAgreementSignDetailItem> + <MineAgreementSignDetailItem label="绌洪棽鏃堕棿"> + <template #detail> + <div class="mine-curriculum-intention-bold">涓嶉檺</div> + </template> + </MineAgreementSignDetailItem> + <MineAgreementSignDetailItem label="姹傝亴鐘舵��"> + <template #detail> + <div class="mine-curriculum-intention-bold">绉瀬鎵惧伐浣�</div> + </template> + </MineAgreementSignDetailItem> </div> + + <ListItem title="璧勬牸璇佷功"> + <template #extra> + <div class="mine-curriculum-intention-enit-btn">缂栬緫</div> + </template> + </ListItem> + <ListItem title="宸ヤ綔缁忛獙"> + <template #extra> + <div class="mine-curriculum-intention-enit-btn">缂栬緫</div> + </template> + </ListItem> + <ListItem title="璇︾粏淇℃伅" class="mine-curriculum-intention-detail"> + <template #extra> + <div class="mine-curriculum-intention-enit-btn">缂栬緫</div> + </template> + </ListItem> </List> - <ListItem title="璧勬牸璇佷功"> - <template #extra> - <div class="user-account">缂栬緫</div> - </template> - </ListItem> </ContentView> </template> <script setup lang="ts"> import { useUserStore } from '@/stores/modules/user'; import { useIsLogin } from '@/hooks'; +import MineAgreementSignDetailItem from '../mineAgreementSignDetail/MineAgreementSignDetailItem.vue'; import { List, ListItem } from '@12333/components'; +import { RouterPath } from '@/constants'; import IconArrow from '@/assets/setting/icon-arrow.png'; import IconAuth from '@/assets/mine/icon-auth.png'; +import Taro from '@tarojs/taro'; defineOptions({ name: 'InnerPage', @@ -64,6 +100,12 @@ const userStore = useUserStore(); const isLogin = useIsLogin(); + +function goEditMineInfo() { + Taro.navigateTo({ + url: RouterPath.editMineInfo, + }); +} </script> <style lang="scss"> @@ -97,6 +139,7 @@ .mine-curriculum-info-item-name { font-size: 32px; line-height: 40px; + font-weight: 600; color: boleGetCssVar('text-color', 'primary'); } @@ -118,6 +161,7 @@ .mine-curriculum-info-item-phone { font-size: 28px; line-height: 40px; + font-weight: 400; color: boleGetCssVar('text-color', 'primary'); } @@ -135,4 +179,77 @@ } } } + +.mine-curriculum-intention { + padding: 30px 0; + border-radius: 12px; + + .mine-curriculum-intention-content { + padding: 0 boleGetCssVar('size', 'body-padding-h') 40px; + border-bottom: 1px solid #f6f6f6; + + .mine-curriculum-intention-title { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 40px; + + .mine-curriculum-intention-title-text { + font-size: 32px; + font-weight: 600; + color: boleGetCssVar('text-color', 'primary'); + } + + .mine-curriculum-intention-title-edit { + display: inline-flex; + align-items: center; + font-size: 22px; + color: boleGetCssVar('text-color', 'regular'); + + .mine-curriculum-intention-title-edit-icon { + width: 32px; + height: 32px; + } + } + } + + .mine-curriculum-intention-job { + align-items: flex-start; + + .mine-curriculum-intention-job-content { + display: inline-flex; + flex-wrap: wrap; + + .mine-curriculum-intention-job-item { + font-size: 20px; + color: boleGetCssVar('color', 'primary'); + padding: 6px 16px; + background-color: #edf2ff; + border-radius: 4px; + display: inline-flex; + align-items: center; + justify-content: center; + margin-right: 16px; + margin-bottom: 14px; + } + } + } + + .mine-curriculum-intention-bold { + font-weight: 600; + font-size: 28px; + } + } + + .mine-curriculum-intention-enit-btn { + font-size: 22px; + color: boleGetCssVar('text-color', 'regular'); + } + + .mine-curriculum-intention-detail { + .pro-list-item-inner { + border-bottom: none; + } + } +} </style> -- Gitblit v1.9.1