first commit
This commit is contained in:
205
src/pages/toolbox/category.vue
Normal file
205
src/pages/toolbox/category.vue
Normal file
@@ -0,0 +1,205 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { toolboxCategories, getCategoryAllTools } from '@/config/toolboxRegistry'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '分类工具',
|
||||
navigationStyle: 'default',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
navigationBarTextStyle: 'black',
|
||||
},
|
||||
})
|
||||
|
||||
const categoryKey = ref('')
|
||||
const category = ref<any>(null)
|
||||
const tools = ref<any[]>([])
|
||||
|
||||
onLoad((query) => {
|
||||
const key = (query?.category as string) || ''
|
||||
categoryKey.value = key
|
||||
|
||||
const cat = toolboxCategories.find(c => c.key === key)
|
||||
if (cat) {
|
||||
category.value = cat
|
||||
tools.value = getCategoryAllTools(key)
|
||||
uni.setNavigationBarTitle({ title: cat.name })
|
||||
}
|
||||
})
|
||||
|
||||
function goTool(key: string) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/toolbox/query?key=${encodeURIComponent(key)}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="page-root">
|
||||
<scroll-view scroll-y class="scrollarea">
|
||||
<view class="page">
|
||||
<view v-if="category" class="cat-header">
|
||||
<view class="cat-icon-large" :style="{ background: `${category.color}15` }">
|
||||
<view :class="['icon', category.icon]" :style="{ color: category.color }" />
|
||||
</view>
|
||||
<view class="cat-info">
|
||||
<text class="cat-name">{{ category.name }}</text>
|
||||
<text class="cat-count">共 {{ tools.length }} 个工具</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="tool-list">
|
||||
<view
|
||||
v-for="item in tools"
|
||||
:key="item.key"
|
||||
class="tool-item"
|
||||
@tap="goTool(item.key)"
|
||||
>
|
||||
<view class="item-icon-wrap" :style="{ background: category ? `${category.color}12` : '#e8f0fe' }">
|
||||
<view :class="['item-icon', item.icon]" :style="{ color: category?.color || '#1768ff' }" />
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<text class="item-name">{{ item.name }}</text>
|
||||
<text class="item-desc">{{ item.desc }}</text>
|
||||
</view>
|
||||
<!-- <text class="item-arrow"></text> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-root {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, #f8faff 0%, #f3f5fb 100%);
|
||||
}
|
||||
|
||||
.scrollarea {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 24rpx 24rpx 40rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cat-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 28rpx 32rpx;
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f7f8ff 100%);
|
||||
border-radius: 24rpx;
|
||||
border: 1rpx solid #e5e6f0;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow:
|
||||
0 16rpx 40rpx rgba(15, 35, 52, 0.04),
|
||||
0 0 0 1rpx rgba(255, 255, 255, 0.5) inset;
|
||||
}
|
||||
|
||||
.cat-icon-large {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 44rpx;
|
||||
}
|
||||
|
||||
.cat-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cat-name {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.cat-count {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.tool-list {
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f7f8ff 100%);
|
||||
border-radius: 24rpx;
|
||||
border: 1rpx solid #e5e6f0;
|
||||
overflow: hidden;
|
||||
box-shadow:
|
||||
0 16rpx 40rpx rgba(15, 35, 52, 0.04),
|
||||
0 0 0 1rpx rgba(255, 255, 255, 0.5) inset;
|
||||
}
|
||||
|
||||
.tool-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 24rpx 28rpx;
|
||||
border-bottom: 1rpx solid #f2f3f5;
|
||||
}
|
||||
|
||||
.tool-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tool-item:active {
|
||||
background: #f7f8fa;
|
||||
}
|
||||
|
||||
.item-icon-wrap {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 18rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
font-size: 34rpx;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
display: block;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #1d2129;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #86909c;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
font-size: 24rpx;
|
||||
color: #c9cdd4;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
199
src/pages/toolbox/index.vue
Normal file
199
src/pages/toolbox/index.vue
Normal file
@@ -0,0 +1,199 @@
|
||||
<script setup lang="ts">
|
||||
import { toolboxCategories, getCategoryHotTools } from '@/config/toolboxRegistry'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '实用工具',
|
||||
navigationStyle: 'default',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
navigationBarTextStyle: 'black',
|
||||
},
|
||||
})
|
||||
|
||||
function goTool(key: string) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/toolbox/query?key=${encodeURIComponent(key)}`,
|
||||
})
|
||||
}
|
||||
|
||||
function goCategory(categoryKey: string) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/toolbox/category?category=${encodeURIComponent(categoryKey)}`,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="page-root">
|
||||
<scroll-view scroll-y class="scrollarea">
|
||||
<view class="page">
|
||||
<view
|
||||
v-for="cat in toolboxCategories"
|
||||
:key="cat.key"
|
||||
class="card"
|
||||
>
|
||||
<!-- 分类标题 -->
|
||||
<view class="card-header" @tap="goCategory(cat.key)">
|
||||
<view class="card-header-left">
|
||||
<view class="cat-icon-wrap" :style="{ background: `${cat.color}15` }">
|
||||
<view :class="['cat-icon', cat.icon]" :style="{ color: cat.color }" />
|
||||
</view>
|
||||
<text class="card-title">{{ cat.name }}</text>
|
||||
</view>
|
||||
<view class="card-more">
|
||||
<text class="more-text">查看更多</text>
|
||||
<!-- <text class="more-arrow">></text> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 热门工具网格 -->
|
||||
<view class="tool-grid">
|
||||
<view
|
||||
v-for="item in getCategoryHotTools(cat.key)"
|
||||
:key="item.key"
|
||||
class="tool-cell"
|
||||
@tap="goTool(item.key)"
|
||||
>
|
||||
<view class="tool-icon-wrap" :style="{ background: `${cat.color}12` }">
|
||||
<view :class="['tool-icon', item.icon]" :style="{ color: cat.color }" />
|
||||
</view>
|
||||
<text class="tool-name">{{ item.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-root {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, #f8faff 0%, #f3f5fb 100%);
|
||||
}
|
||||
|
||||
.scrollarea {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 24rpx 24rpx 40rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f7f8ff 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx 24rpx 20rpx;
|
||||
margin-bottom: 24rpx;
|
||||
border: 1rpx solid #e5e6f0;
|
||||
box-shadow:
|
||||
0 16rpx 40rpx rgba(15, 35, 52, 0.04),
|
||||
0 0 0 1rpx rgba(255, 255, 255, 0.5) inset;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.card-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.cat-icon-wrap {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cat-icon {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
.card-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
background: #f2f3f5;
|
||||
}
|
||||
|
||||
.more-text {
|
||||
font-size: 22rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.more-arrow {
|
||||
font-size: 22rpx;
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
.card-more:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.tool-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -6rpx;
|
||||
}
|
||||
|
||||
.tool-cell {
|
||||
width: 33.333%;
|
||||
padding: 6rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-top: 12rpx;
|
||||
padding-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.tool-cell:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.tool-icon-wrap {
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.tool-icon {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.tool-name {
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
color: #1d2129;
|
||||
text-align: center;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
610
src/pages/toolbox/query.vue
Normal file
610
src/pages/toolbox/query.vue
Normal file
@@ -0,0 +1,610 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getToolboxItem } from '@/config/toolboxRegistry'
|
||||
import { postToolboxQuery } from '@/api/toolbox'
|
||||
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '工具查询',
|
||||
navigationStyle: 'default',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
navigationBarTextStyle: 'black',
|
||||
enablePullDownRefresh: false,
|
||||
},
|
||||
})
|
||||
|
||||
const toolKey = ref('')
|
||||
const tool = ref<ReturnType<typeof getToolboxItem>>(null)
|
||||
|
||||
const form = ref<Record<string, string>>({})
|
||||
const loading = ref(false)
|
||||
const result = ref<Record<string, any> | null>(null)
|
||||
const error = ref('')
|
||||
|
||||
// 选择框相关状态
|
||||
const popup = ref<any>(null)
|
||||
const currentField = ref<any>(null)
|
||||
const pickerValue = ref([0])
|
||||
const indicatorStyle = `'height: 50px'`
|
||||
|
||||
onLoad((query) => {
|
||||
const key = (query?.key as string) || ''
|
||||
toolKey.value = key
|
||||
tool.value = getToolboxItem(key)
|
||||
if (!tool.value) {
|
||||
error.value = '未找到该工具'
|
||||
}
|
||||
else {
|
||||
uni.setNavigationBarTitle({ title: tool.value.name })
|
||||
|
||||
// 初始化表单默认值
|
||||
if (tool.value.fields) {
|
||||
tool.value.fields.forEach(field => {
|
||||
if (field.default !== undefined && !form.value[field.key]) {
|
||||
form.value[field.key] = field.default
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 如果工具标记了自动查询或不需要输入参数,打开即查
|
||||
if (tool.value.autoQuery || tool.value.fields.length === 0) {
|
||||
handleQuery()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 获取选择框当前选中项的索引
|
||||
function getSelectIndex(field, value) {
|
||||
if (!field.options || !Array.isArray(field.options)) {
|
||||
return 0
|
||||
}
|
||||
const defaultValue = field.options[0]?.value || ''
|
||||
const targetValue = value || defaultValue
|
||||
return field.options.findIndex(opt => opt.value === targetValue)
|
||||
}
|
||||
|
||||
// 获取选择框当前选中项的标签
|
||||
function getSelectedLabel(field, value) {
|
||||
if (!field.options || !Array.isArray(field.options) || !value) {
|
||||
return null
|
||||
}
|
||||
const option = field.options.find(opt => opt.value === value)
|
||||
return option ? option.label : null
|
||||
}
|
||||
|
||||
// 显示自定义选择器
|
||||
function showPicker(field) {
|
||||
currentField.value = field
|
||||
const currentValue = form.value[field.key] || field.options[0]?.value || ''
|
||||
const index = field.options.findIndex(opt => opt.value === currentValue)
|
||||
pickerValue.value = [index]
|
||||
popup.value.open()
|
||||
}
|
||||
|
||||
// 关闭选择器
|
||||
function closePicker() {
|
||||
popup.value.close()
|
||||
}
|
||||
|
||||
// 确认选择
|
||||
function confirmPicker() {
|
||||
if (currentField.value) {
|
||||
const index = pickerValue.value[0]
|
||||
form.value[currentField.value.key] = currentField.value.options[index].value
|
||||
closePicker()
|
||||
}
|
||||
}
|
||||
|
||||
// 选择器变化处理
|
||||
function onPickerChange(e) {
|
||||
pickerValue.value = e.detail.value
|
||||
}
|
||||
|
||||
async function handleQuery() {
|
||||
if (!tool.value)
|
||||
return
|
||||
|
||||
error.value = ''
|
||||
result.value = null
|
||||
revealedKeys.value = new Set()
|
||||
|
||||
if (!tool.value.validate(form.value)) {
|
||||
error.value = tool.value.validateMsg
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await postToolboxQuery(toolKey.value, form.value)
|
||||
if (res.code === 200 && res.data?.result) {
|
||||
result.value = res.data.result
|
||||
}
|
||||
else {
|
||||
error.value = res.msg || '查询失败'
|
||||
}
|
||||
}
|
||||
catch {
|
||||
error.value = '网络错误,请稍后重试'
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resultEntries = computed(() => {
|
||||
if (!result.value || !tool.value?.resultLabels)
|
||||
return []
|
||||
return Object.entries(tool.value.resultLabels)
|
||||
.filter(([key]) => result.value![key] !== undefined)
|
||||
.map(([key, labelOrObj]) => {
|
||||
const val = result.value![key]
|
||||
const display = val === '' || val === null ? '无' : val
|
||||
if (typeof labelOrObj === 'object' && labelOrObj !== null) {
|
||||
return { key, label: labelOrObj.label, hidden: !!labelOrObj.hidden, value: display }
|
||||
}
|
||||
return { key, label: labelOrObj, hidden: false, value: display }
|
||||
})
|
||||
})
|
||||
|
||||
const revealedKeys = ref<Set<string>>(new Set())
|
||||
|
||||
function toggleReveal(key: string) {
|
||||
if (revealedKeys.value.has(key)) {
|
||||
revealedKeys.value.delete(key)
|
||||
}
|
||||
else {
|
||||
revealedKeys.value.add(key)
|
||||
}
|
||||
}
|
||||
|
||||
const resultList = computed(() => {
|
||||
if (!result.value || tool.value?.resultType !== 'list')
|
||||
return []
|
||||
const list = result.value.list
|
||||
if (!Array.isArray(list))
|
||||
return []
|
||||
return list
|
||||
})
|
||||
|
||||
const listLabelEntries = computed(() => {
|
||||
if (!tool.value?.resultLabels)
|
||||
return []
|
||||
return Object.entries(tool.value.resultLabels)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="page-root">
|
||||
<scroll-view scroll-y class="scrollarea">
|
||||
<view class="page">
|
||||
<view v-if="tool" class="card">
|
||||
<view class="card-desc">
|
||||
<text class="desc-text">{{ tool.desc }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 动态表单 -->
|
||||
<view class="form-area">
|
||||
<view v-for="field in tool.fields" :key="field.key" class="field">
|
||||
<text class="field-label">{{ field.label }}</text>
|
||||
|
||||
<!-- 选择框 -->
|
||||
<picker
|
||||
v-if="field.type === 'select'"
|
||||
mode="selector"
|
||||
:range="field.options.map(opt => opt.label)"
|
||||
:value="getSelectIndex(field, form[field.key])"
|
||||
@change="(e: any) => {
|
||||
const index = e.detail.value
|
||||
form[field.key] = field.options[index].value
|
||||
}"
|
||||
>
|
||||
<view class="field-input field-picker">
|
||||
{{ getSelectedLabel(field, form[field.key]) || field.placeholder }}
|
||||
</view>
|
||||
</picker>
|
||||
|
||||
<!-- 日期选择器 -->
|
||||
<picker
|
||||
v-else-if="field.type === 'date'"
|
||||
mode="date"
|
||||
:value="form[field.key] || ''"
|
||||
@change="(e: any) => (form[field.key] = e.detail.value)"
|
||||
>
|
||||
<view class="field-input field-picker">
|
||||
{{ form[field.key] || field.placeholder }}
|
||||
</view>
|
||||
</picker>
|
||||
|
||||
<!-- 文本域 -->
|
||||
<textarea
|
||||
v-else-if="field.type === 'textarea'"
|
||||
class="field-input field-textarea"
|
||||
:maxlength="field.maxlength"
|
||||
:placeholder="field.placeholder"
|
||||
:value="form[field.key] || ''"
|
||||
placeholder-class="field-ph"
|
||||
@input="(e: any) => (form[field.key] = e.detail.value)"
|
||||
/>
|
||||
|
||||
<!-- 普通输入框 -->
|
||||
<input
|
||||
v-else
|
||||
class="field-input"
|
||||
:type="field.type"
|
||||
:maxlength="field.maxlength"
|
||||
:placeholder="field.placeholder"
|
||||
:value="form[field.key] || ''"
|
||||
placeholder-class="field-ph"
|
||||
confirm-type="done"
|
||||
@input="(e: any) => (form[field.key] = e.detail.value)"
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 查询按钮 -->
|
||||
<button
|
||||
class="query-btn"
|
||||
:disabled="loading"
|
||||
@tap="handleQuery"
|
||||
>
|
||||
{{ loading ? '查询中...' : '立即查询' }}
|
||||
</button>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view v-if="error" class="msg-area msg-error">
|
||||
<text class="msg-text">{{ error }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 结果展示 - 普通键值对 -->
|
||||
<view v-if="resultEntries.length > 0 && tool?.resultType !== 'list'" class="result-area">
|
||||
<view class="result-title">查询结果</view>
|
||||
<view class="result-list">
|
||||
<view
|
||||
v-for="item in resultEntries"
|
||||
:key="item.key"
|
||||
class="result-row"
|
||||
>
|
||||
<text class="result-label">{{ item.label }}</text>
|
||||
<!-- 隐藏字段:点击显示/隐藏 -->
|
||||
<view v-if="item.hidden" class="result-reveal-wrap">
|
||||
<view
|
||||
v-if="!revealedKeys.has(item.key)"
|
||||
class="result-reveal-btn"
|
||||
@tap="toggleReveal(item.key)"
|
||||
>
|
||||
点击查看
|
||||
</view>
|
||||
<template v-else>
|
||||
<text class="result-value">{{ item.value }}</text>
|
||||
<text class="result-hide-btn" @tap="toggleReveal(item.key)">收起</text>
|
||||
</template>
|
||||
</view>
|
||||
<!-- 普通字段 -->
|
||||
<text v-else class="result-value">{{ item.value }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 结果展示 - 列表型 -->
|
||||
<view v-if="resultList.length > 0" class="result-area">
|
||||
<view class="result-title">查询结果</view>
|
||||
<view class="result-card-list">
|
||||
<view
|
||||
v-for="(item, idx) in resultList"
|
||||
:key="idx"
|
||||
class="result-card-item"
|
||||
>
|
||||
<view
|
||||
v-for="([fieldKey, fieldLabel], fIdx) in listLabelEntries"
|
||||
:key="fieldKey"
|
||||
class="card-item-row"
|
||||
>
|
||||
<template v-if="item[fieldKey] !== undefined && item[fieldKey] !== ''">
|
||||
<text v-if="fIdx === 0" class="card-item-index">{{ idx + 1 }}</text>
|
||||
<text v-else class="card-item-index-placeholder" />
|
||||
<text class="card-item-field-label">{{ typeof fieldLabel === 'object' ? fieldLabel.label : fieldLabel }}</text>
|
||||
<text class="card-item-field-value">{{ item[fieldKey] }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="empty">
|
||||
<text class="empty-text">未找到该工具</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-root {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(180deg, #f8faff 0%, #f3f5fb 100%);
|
||||
}
|
||||
|
||||
.scrollarea {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: 24rpx 24rpx 40rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: linear-gradient(145deg, #ffffff 0%, #f7f8ff 100%);
|
||||
border-radius: 24rpx;
|
||||
padding: 32rpx 28rpx;
|
||||
border: 1rpx solid #e5e6f0;
|
||||
box-shadow:
|
||||
0 16rpx 40rpx rgba(15, 35, 52, 0.04),
|
||||
0 0 0 1rpx rgba(255, 255, 255, 0.5) inset;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.desc-text {
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.form-area {
|
||||
margin-bottom: 28rpx;
|
||||
}
|
||||
|
||||
.field {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.field-label {
|
||||
display: block;
|
||||
font-size: 24rpx;
|
||||
color: #4e5969;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.field-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: #f7f8fa;
|
||||
border: 1rpx solid #e5e6f0;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1d2129;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.field-picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #1d2129;
|
||||
}
|
||||
|
||||
.field-picker:empty::before {
|
||||
content: attr(placeholder);
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
.field-textarea {
|
||||
height: 200rpx;
|
||||
padding: 16rpx 24rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.field-ph {
|
||||
color: #c9cdd4;
|
||||
}
|
||||
|
||||
.query-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background: linear-gradient(135deg, #1768ff, #4e8cff);
|
||||
color: #ffffff;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
border-radius: 16rpx;
|
||||
border: none;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.query-btn[disabled] {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.msg-area {
|
||||
padding: 16rpx 20rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.msg-error {
|
||||
background: #fff2f0;
|
||||
border: 1rpx solid #ffccc7;
|
||||
}
|
||||
|
||||
.msg-text {
|
||||
font-size: 24rpx;
|
||||
color: #f53f3f;
|
||||
}
|
||||
|
||||
.result-area {
|
||||
margin-top: 8rpx;
|
||||
padding-top: 24rpx;
|
||||
border-top: 1rpx solid #f2f3f5;
|
||||
}
|
||||
|
||||
.result-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.result-list {
|
||||
background: #f7f8fa;
|
||||
border-radius: 16rpx;
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
|
||||
.result-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 26rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-size: 26rpx;
|
||||
color: #1d2129;
|
||||
font-weight: 500;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.result-reveal-wrap {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.result-reveal-btn {
|
||||
font-size: 24rpx;
|
||||
color: #ffffff;
|
||||
background: linear-gradient(135deg, #1768ff, #4e8cff);
|
||||
padding: 6rpx 24rpx;
|
||||
border-radius: 24rpx;
|
||||
}
|
||||
|
||||
.result-hide-btn {
|
||||
font-size: 22rpx;
|
||||
color: #86909c;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 120rpx 0;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #86909c;
|
||||
}
|
||||
|
||||
/* 列表型结果卡片 */
|
||||
.result-card-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.result-card-item {
|
||||
background: #ffffff;
|
||||
border: 1rpx solid #e5e6f0;
|
||||
border-radius: 16rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
}
|
||||
|
||||
.card-item-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12rpx;
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
.card-item-index {
|
||||
flex-shrink: 0;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
text-align: center;
|
||||
background: linear-gradient(135deg, #1768ff, #4e8cff);
|
||||
color: #ffffff;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.card-item-index-placeholder {
|
||||
flex-shrink: 0;
|
||||
width: 40rpx;
|
||||
}
|
||||
|
||||
.card-item-field-label {
|
||||
flex-shrink: 0;
|
||||
font-size: 24rpx;
|
||||
color: #86909c;
|
||||
min-width: 80rpx;
|
||||
}
|
||||
|
||||
.card-item-field-value {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: #1d2129;
|
||||
line-height: 1.6;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 自定义选择器样式 */
|
||||
.picker-container {
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.picker-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
height: 88rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.picker-header text {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.picker-header text:first-child {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.picker-header text:last-child {
|
||||
color: #1768ff;
|
||||
}
|
||||
|
||||
.picker-view {
|
||||
width: 100%;
|
||||
height: 400rpx;
|
||||
}
|
||||
|
||||
.picker-item {
|
||||
line-height: 100rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user