为了端到端验证 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 正确旁挂。
83 lines
2.5 KiB
Vue
83 lines
2.5 KiB
Vue
<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>
|