chore: initial commit
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<view class="popup-header">
|
||||
<view class="popup-header-spacer" aria-hidden="true"></view>
|
||||
<text class="popup-header-title" :class="{ 'popup-header-title-danger': tone === 'danger' }">{{ title }}</text>
|
||||
<button class="popup-header-close" :aria-label="`关闭${title}`" @tap="$emit('close')">
|
||||
<uni-icons type="closeempty" color="#52657c" size="24" />
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ['close'],
|
||||
props: {
|
||||
title: { type: String, required: true },
|
||||
tone: { type: String, default: 'default' }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.popup-header { display: grid; min-height: 48px; align-items: center; grid-template-columns: 48px minmax(0, 1fr) 48px; }
|
||||
.popup-header-title { display: block; color: #1f2937; font-size: 17px; font-weight: 700; line-height: 24px; text-align: center; }
|
||||
.popup-header-title-danger { color: #b42318; }
|
||||
.popup-header-close { display: flex; width: 48px; height: 48px; margin: 0; padding: 0; align-items: center; justify-content: center; border: 0; border-radius: 8px; line-height: 48px; background: transparent; }
|
||||
.popup-header-close::after { border: 0; }
|
||||
.popup-header-close:active { background: #eef2f6; }
|
||||
</style>
|
||||
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<view class="portal-header-shell">
|
||||
<view class="portal-header">
|
||||
<view class="portal-header-row">
|
||||
<button v-if="menu" class="portal-header-button" aria-label="打开功能菜单" @tap="openMenu"><uni-icons type="bars" color="#ffffff" size="26" /></button>
|
||||
<button v-else class="portal-header-button" aria-label="返回上一页" @tap="goBack"><uni-icons type="back" color="#ffffff" size="26" /></button>
|
||||
<text class="portal-title">{{ title }}</text>
|
||||
<button v-if="showProfile" class="avatar-button" aria-label="打开个人中心" @tap="goProfile"><uni-icons type="person" color="#ffffff" size="27" /></button>
|
||||
<view v-else class="portal-header-spacer" aria-hidden="true"></view>
|
||||
</view>
|
||||
</view>
|
||||
<uni-popup ref="menuPopup" type="bottom" background-color="#ffffff" border-radius="12px 12px 0 0" :is-mask-click="true" @change="handleMenuChange">
|
||||
<view class="header-menu-sheet">
|
||||
<view class="header-menu-content">
|
||||
<PopupHeader title="功能菜单" @close="closeMenu" />
|
||||
<button class="header-menu-item" @tap="goHistory"><uni-icons type="list" color="#334155" size="22" /><text>作业记录</text><uni-icons type="right" color="#94a3b8" size="18" /></button>
|
||||
<button class="header-menu-item" @tap="goProfile"><uni-icons type="person" color="#334155" size="22" /><text>个人中心</text><uni-icons type="right" color="#94a3b8" size="18" /></button>
|
||||
<button class="header-menu-close" @tap="closeMenu">关闭</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { navigateBackOr, navigateToUnique } from '@/utils/navigation.js'
|
||||
import PopupHeader from '@/components/PopupHeader.vue'
|
||||
|
||||
export default {
|
||||
components: { PopupHeader },
|
||||
emits: ['menu-change'],
|
||||
props: {
|
||||
title: { type: String, required: true },
|
||||
user: { type: Object, required: true },
|
||||
menu: Boolean,
|
||||
showProfile: { type: Boolean, default: true },
|
||||
fallbackUrl: { type: String, default: '/pages/home/home' }
|
||||
},
|
||||
methods: {
|
||||
goBack() { navigateBackOr(this.fallbackUrl) },
|
||||
goProfile() { this.closeMenu(); navigateToUnique('/pages/profile/profile') },
|
||||
goHistory() { this.closeMenu(); navigateToUnique('/pages/history/history') },
|
||||
openMenu() { this.$refs.menuPopup.open() },
|
||||
closeMenu() { if (this.$refs.menuPopup) this.$refs.menuPopup.close() },
|
||||
handleMenuChange(event) { this.$emit('menu-change', Boolean(event.show)) }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<view
|
||||
class="scan-target-input"
|
||||
:class="{ 'scan-target-input-active': active }"
|
||||
@tap="$emit('activate', name)"
|
||||
>
|
||||
<view class="scan-target-icon" aria-hidden="true">
|
||||
<view class="scan-target-corner corner-tl"></view>
|
||||
<view class="scan-target-corner corner-tr"></view>
|
||||
<view class="scan-target-corner corner-bl"></view>
|
||||
<view class="scan-target-corner corner-br"></view>
|
||||
<view class="scan-target-line"></view>
|
||||
</view>
|
||||
<input
|
||||
class="scan-target-value"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
:aria-label="`${label},支持扫码或人工输入`"
|
||||
confirm-type="done"
|
||||
@focus="$emit('activate', name)"
|
||||
@input="handleInput"
|
||||
@confirm="handleConfirm"
|
||||
/>
|
||||
<text v-if="active" class="scan-target-badge">当前扫码</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ['activate', 'update:modelValue', 'submit'],
|
||||
props: {
|
||||
name: { type: String, required: true },
|
||||
modelValue: { type: String, default: '' },
|
||||
label: { type: String, default: '扫码输入框' },
|
||||
placeholder: { type: String, default: '扫描或人工输入' },
|
||||
active: Boolean
|
||||
},
|
||||
methods: {
|
||||
handleInput(event) { this.$emit('update:modelValue', event.detail.value) },
|
||||
handleConfirm(event) { this.$emit('submit', event.detail.value) }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.scan-target-input { position: relative; box-sizing: border-box; width: 100%; height: 48px; border: 1px solid #cfd8e3; border-radius: 8px; background: #ffffff; }
|
||||
.scan-target-input-active { border: 2px solid #135ee8; background: #f8fbff; box-shadow: 0 0 0 2px rgba(19, 94, 232, 0.14); }
|
||||
.scan-target-icon { position: absolute; z-index: 1; left: 12px; top: 12px; width: 22px; height: 22px; color: #8190a3; pointer-events: none; }
|
||||
.scan-target-input-active .scan-target-icon { left: 11px; top: 11px; color: #135ee8; }
|
||||
.scan-target-corner { position: absolute; box-sizing: border-box; width: 6px; height: 6px; border-color: currentColor; }
|
||||
.corner-tl { top: 0; left: 0; border-top: 2px solid; border-left: 2px solid; }
|
||||
.corner-tr { top: 0; right: 0; border-top: 2px solid; border-right: 2px solid; }
|
||||
.corner-bl { bottom: 0; left: 0; border-bottom: 2px solid; border-left: 2px solid; }
|
||||
.corner-br { right: 0; bottom: 0; border-right: 2px solid; border-bottom: 2px solid; }
|
||||
.scan-target-line { position: absolute; left: 4px; top: 10px; width: 14px; height: 2px; background: currentColor; }
|
||||
.scan-target-value { box-sizing: border-box; width: 100%; height: 46px; padding: 0 82px 0 42px; border: 0; color: #27384d; font-size: 15px; background: transparent; }
|
||||
.scan-target-badge { position: absolute; right: 8px; top: 12px; padding: 3px 6px; border-radius: 4px; color: #135ee8; font-size: 10px; font-weight: 700; line-height: 16px; pointer-events: none; background: #e7f0ff; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user