demo: 加 Vue 前端到 examples/basic-admin/web
为了端到端验证 Shrimp 框架,把 hand-admin 前端拷进 examples/basic-admin/web
作为临时演示用前端,@shrimp alias 直接指向同仓 src/,免构建。
修改要点:
- web/vite.config.ts: @shrimp 改成 ../../../src; proxy /admin-api 到 :3100
- web/tsconfig.json: 同步 @shrimp 路径; 删掉 hand-server-2 的 paths
- web/src/locales: 删掉 matter_*/zerobase 业务 key
- web/src/module: 删掉 matter_*/zerobase 业务 vue,只留 user/role/FieldRelativeTime
- examples/basic-admin/index.ts:
- mount 到 /admin-api/* 而不是 /api/*
- 加 /config /login /me 端点 (mock super-admin operator,固定 token)
- DemoShrimp 子类覆盖 getMenuTree 用模块自身 label
- MemoryShrimpCrud 的 getRelatedCrud 手动 wire 到 crudRegistry,
populate 才能跑 (后续 70→90 改进项)
curl 已验证 /config /login /me /product/list 全通,tagIds_label 正确旁挂。
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<template v-if="mode === 'display'">
|
||||
<template v-if="Array.isArray(modelValue)">{{ modelValue.join(', ') || 0 }}</template>
|
||||
<template v-else>{{ modelValue ?? 0 }}</template>
|
||||
</template>
|
||||
<div v-else-if="mode === 'filter'" style="display: flex; gap: 8px; align-items: center; width: 100%">
|
||||
<el-input-number
|
||||
:model-value="modelValue?.min"
|
||||
@update:model-value="emitRange('min', $event)"
|
||||
:placeholder="$t('table.min')"
|
||||
controls-position="right"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<span style="color: #999">~</span>
|
||||
<el-input-number
|
||||
:model-value="modelValue?.max"
|
||||
@update:model-value="emitRange('max', $event)"
|
||||
:placeholder="$t('table.max')"
|
||||
controls-position="right"
|
||||
style="flex: 1"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="field.multiple" class="tags-input">
|
||||
<el-tag v-for="(num, index) in (modelValue || [])" :key="num + '-' + index" closable @close="removeNum(index)">
|
||||
{{ num }}
|
||||
</el-tag>
|
||||
<el-input-number
|
||||
v-model="inputValue"
|
||||
@keyup.enter="addNum"
|
||||
@blur="addNum"
|
||||
:placeholder="$t('table.pressEnterForNumber')"
|
||||
:controls="false"
|
||||
style="width: 120px; flex: 1; min-width: 120px"
|
||||
/>
|
||||
</div>
|
||||
<el-input-number v-else :model-value="modelValue" @update:model-value="$emit('update:modelValue', $event)" :disabled="disabled" style="width: 100%" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
field: any
|
||||
modelValue: any
|
||||
mode: 'display' | 'edit' | 'filter'
|
||||
disabled?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: any]
|
||||
}>()
|
||||
|
||||
const inputValue = ref<number | undefined>(undefined)
|
||||
|
||||
function emitRange(key: 'min' | 'max', val: number | undefined) {
|
||||
const current = props.modelValue || {}
|
||||
emit('update:modelValue', { ...current, [key]: val })
|
||||
}
|
||||
|
||||
function addNum() {
|
||||
if (inputValue.value == null) return
|
||||
const current = Array.isArray(props.modelValue) ? props.modelValue : []
|
||||
emit('update:modelValue', [...current, inputValue.value])
|
||||
inputValue.value = undefined
|
||||
}
|
||||
|
||||
function removeNum(index: number) {
|
||||
const current = Array.isArray(props.modelValue) ? [...props.modelValue] : []
|
||||
current.splice(index, 1)
|
||||
emit('update:modelValue', current)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tags-input {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user