feat(data-input): 新增输入指标管理

- 输入指标改为数据库管理并绑定到药品数据
This commit is contained in:
LittleBoy 2025-07-20 14:56:11 +08:00
parent 6252553aee
commit 8632c1c606
17 changed files with 545 additions and 350 deletions

View File

@ -16,7 +16,7 @@
"@tiptap/vue-3": "^2.10.4", "@tiptap/vue-3": "^2.10.4",
"ant-design-vue": "^4.2.6", "ant-design-vue": "^4.2.6",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"axios": "^1.7.9", "axios": "^1.8.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"js-md5": "^0.8.3", "js-md5": "^0.8.3",
"pinia": "^2.3.0", "pinia": "^2.3.0",

View File

@ -1,179 +1,194 @@
<template> <template>
<div class="calc-container"> <div class="calc-container">
<div class="setting-container"> <div class="setting-container">
<div class="grid list-container grid-cols-2 gap-4 py-2"> <div class="grid list-container grid-cols-2 gap-4 py-2">
<div class="input-item"> <div class="input-item">
<div class="title">体重</div> <div class="title">体重</div>
<div class="input"> <div class="input">
<input type="number" v-model="commonValues.weight" placeholder="单位(kg)"/> <input type="number" v-model="commonValues.weight" placeholder="单位(kg)"/>
</div> </div>
</div> </div>
<div class="input-item"> <div class="input-item">
<div class="title">24h尿素</div> <div class="title">24h尿素</div>
<div class="input"> <div class="input">
<input type="number" v-model="commonValues.niaosu" placeholder="单位(mmol)"/> <input type="number" v-model="commonValues.niaosu" placeholder="单位(mmol)"/>
</div> </div>
</div> </div>
</div>
<Tabs>
<TabPane key="gut" tab="肠内制剂">
<div class="grid list-container grid-cols-2 gap-4 py-2 setting-input-scroller">
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='gut')" :key="key">
<div class="title">{{ it.title }}</div>
<div class="input">
<input type="number" v-model="it.value" :placeholder="it.placeholder"/>
<span class="unit">{{ it.unit }}</span>
</div>
</div> </div>
<Tabs> </div>
<TabPane key="gut" tab="肠内制剂"> </TabPane>
<div class="grid list-container grid-cols-2 gap-4 py-2 setting-input-scroller"> <TabPane key="vein" tab="静脉制剂">
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='gut')" :key="key"> <div class="grid list-container grid-cols-2 gap-4 py-2 setting-input-scroller">
<div class="title">{{ it.title }}</div> <div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='vein')" :key="key">
<div class="input"> <div class="title">{{ it.title }}</div>
<input type="number" v-model="it.value" :placeholder="it.placeholder"/> <div class="input">
<span class="unit">{{ it.unit }}</span> <input type="number" v-model="it.value" :placeholder="it.placeholder"/>
</div> <span class="unit">{{ it.unit }}</span>
</div> </div>
</div> </div>
</TabPane> </div>
<TabPane key="vein" tab="静脉制剂"> </TabPane>
<div class="grid list-container grid-cols-2 gap-4 py-2 setting-input-scroller"> </Tabs>
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='vein')" :key="key">
<div class="title">{{ it.title }}</div>
<div class="input">
<input type="number" v-model="it.value" :placeholder="it.placeholder"/>
<span class="unit">{{ it.unit }}</span>
</div>
</div>
</div>
</TabPane>
</Tabs>
</div>
<div class="text-center py-4">
<Button type="primary" @click="calcResult">测试计算</Button>
</div>
<ResultModal v-model:result="testResultValue" />
</div> </div>
<div class="text-center py-4">
<Button type="primary" @click="calcResult">测试计算</Button>
</div>
<ResultModal v-model:result="testResultValue"/>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {onMounted,defineComponent, ref} from "vue"; import {onMounted, defineComponent, ref} from "vue";
import {TabPane, Tabs, Button, Modal} from "ant-design-vue"; import {TabPane, Tabs, Button, Modal} from "ant-design-vue";
import {inputProducts} from "@/pages/result/test/data-input.ts"; // import {inputProducts} from "@/pages/result/test/data-input.ts";
import ResultModal from "@/pages/result/components/result-modal.vue"; import ResultModal from "@/pages/result/components/result-modal.vue";
import {expressionList} from "@/service/api/result.ts"; import {expressionList} from "@/service/api/result.ts";
import {parseExpression} from "@/core/string.ts"; import {parseExpression} from "@/core/string.ts";
import {getAllProduct} from "@/service/use-result-vars.ts"; import {getAllProduct} from "@/service/use-result-vars.ts";
import {getAllProductInput} from "@/service/api/product.ts";
const commonValues = ref({ const commonValues = ref({
weight: '', weight: '',
niaosu: '', niaosu: '',
}) })
defineComponent({ defineComponent({
name: 'Calculation' name: 'Calculation'
}) })
const ResultExpressionList = ref<ResultExpression[]>([]); const ResultExpressionList = ref<ResultExpression[]>([]);
const settingList = ref<SettingItem[]>([]) const settingList = ref<SettingItem[]>([])
const testResultValue = ref<ResultItem[]>([]) const testResultValue = ref<ResultItem[]>([])
const productValues = getAllProduct(); const productValues = getAllProduct();
onMounted(()=>{ onMounted(() => {
expressionList().then((res) => { expressionList().then((res) => {
ResultExpressionList.value = res.list; ResultExpressionList.value = res.list;
}); });
const setting: SettingItem[] = [] initInputList().then(() => {
inputProducts.forEach(it => { console.log("init input setting success")
setting.push({ })
title: it.name,
key: it.key,
value: '',
placeholder: it.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.unit,
})
if (it.addition) {
setting.push({
title: it.name,
key: it.addition.key,
value: '',
placeholder: it.addition.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.addition.unit,
})
}
})
settingList.value = setting
}) })
function runCode(expression: string, vars: any) {
return new Function('vars', `with(vars) { return ${expression};}`)(vars)
} async function initInputList() {
function getResultValues(){
// const setting: SettingItem[] = []
const result:{ const inputProducts = await getAllProductInput();
[key: string]: number inputProducts.forEach(it => {
} = {}; setting.push({
const {niaosu,weight} = commonValues.value title: it.name,
const inputs: { [key: string]: number }= { key: it.key,
niaosu: niaosu ?Number(niaosu): 0, value: '',
weight: weight ?Number(weight): 0, placeholder: it.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.unit,
})
if (it.addition) {
setting.push({
title: it.name,
key: it.addition.key,
value: '',
placeholder: it.addition.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.addition.unit,
})
} }
settingList.value.forEach(it=>{ })
inputs[it.key] = it.value ? Number(it.value) : 0 settingList.value = setting
})
ResultExpressionList.value.forEach(it=>{
const expression = parseExpression(it.expression);
if(expression.length == 0) return;
try{
const value = runCode(expression, {
...(productValues.value),
...result,
input: inputs,
})
result[it.key] = value;
}catch (e) {
Modal.warning({
title: '提示',
content: `计算出错:${(e as Error).message}`
})
console.error('getResultValues',e,expression)
}
})
return result;
} }
function calcResult(){ function runCode(expression: string, vars: any) {
const result = getResultValues(); return new Function('vars', `with(vars) { return ${expression};}`)(vars)
console.log('result',result) }
const resultList:ResultItem[] = [];
ResultExpressionList.value.forEach(it=>{ function getResultValues() {
resultList.push({ //
title:it.title, const result: {
key:it.key, [key: string]: number
value: result[it.key] || 0 } = {};
}) const {niaosu, weight} = commonValues.value
const inputs: { [key: string]: number } = {
niaosu: niaosu ? Number(niaosu) : 0,
weight: weight ? Number(weight) : 0,
}
settingList.value.forEach(it => {
inputs[it.key] = it.value ? Number(it.value) : 0
})
ResultExpressionList.value.forEach(it => {
const expression = parseExpression(it.expression);
if (expression.length == 0) return;
try {
const value = runCode(expression, {
...(productValues.value),
...result,
input: inputs,
})
result[it.key] = value;
} catch (e) {
Modal.warning({
title: '提示',
content: `计算出错:${(e as Error).message}`
})
console.error('getResultValues', e, expression)
}
})
return result;
}
function calcResult() {
const result = getResultValues();
console.log('result', result)
const resultList: ResultItem[] = [];
ResultExpressionList.value.forEach(it => {
resultList.push({
title: it.title,
key: it.key,
value: result[it.key] || 0
}) })
console.log(resultList); })
testResultValue.value = resultList; console.log(resultList);
testResultValue.value = resultList;
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.calc-container{ .calc-container {
max-width: 90%; max-width: 90%;
margin: auto; margin: auto;
width: 600px; width: 600px;
} }
.list-container { .list-container {
margin-right: -4px; margin-right: -4px;
padding-right: 4px; padding-right: 4px;
} }
.setting-input-scroller { .setting-input-scroller {
max-height: calc(100vh - 200px); max-height: calc(100vh - 200px);
overflow: auto; overflow: auto;
} }
.setting-container { .setting-container {
.input { .input {
@apply w-full relative border rounded mt-1 flex items-center bg-white overflow-hidden; @apply w-full relative border rounded mt-1 flex items-center bg-white overflow-hidden;
} }
input { input {
@apply flex-1 outline-0 block ml-2 py-1 mr-1; @apply flex-1 outline-0 block ml-2 py-1 mr-1;
} }
.unit { .unit {
@apply absolute inset-y-0 right-0 px-2 py-1 bg-gray-100 block h-full text-center; @apply absolute inset-y-0 right-0 px-2 py-1 bg-gray-100 block h-full text-center;
min-width: 34px; min-width: 34px;
} }
} }
</style> </style>

View File

@ -65,7 +65,7 @@ onUnmounted(() => {
editor.destroy() editor.destroy()
}) })
</script> </script>
<style> <style lang="scss">
.tiptap { .tiptap {
} }
.tiptap{ .tiptap{

View File

@ -204,7 +204,7 @@ function handleHideModal() {
.menu-item {} .menu-item {}
.menu-icon { .menu-icon {
font-size: 26px; font-size: 30px;
} }
.app-main-container { .app-main-container {

13
src/pages/input/index.vue Normal file
View File

@ -0,0 +1,13 @@
<template>
<div>
<h1>Hello World</h1>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
h1 {
}
</style>

View File

@ -13,9 +13,11 @@ import { ProductCols } from "@/service/api/product";
import { getList, deleteProduct } from "@/service/api/product"; import { getList, deleteProduct } from "@/service/api/product";
import useRequest from "@/service/useRequest"; import useRequest from "@/service/useRequest";
import EditModal from "./edit-modal.vue" import EditModal from "./edit-modal.vue"
import ProductInputModal from "./input/index.vue"
const editProduct = ref<Partial<ProductInfoModel>>(); const editProduct = ref<Partial<ProductInfoModel>>();
const productInput = ref<Partial<ProductInfoModel>>();
// const formState = ref<{name?:string;category?:string}>({ // const formState = ref<{name?:string;category?:string}>({
// }) // })
const searchParams = ref<ProductSearchParam>({ const searchParams = ref<ProductSearchParam>({
@ -90,14 +92,16 @@ function handleSearch(){
<th>制剂别名</th> <th>制剂别名</th>
<th>类型</th> <th>类型</th>
<th v-for="th in ProductCols">{{ th.name }}</th> <th v-for="th in ProductCols">{{ th.name }}</th>
<th width="100" class="text-center">计量单位</th> <th width="100">计量单位</th>
<th width="150" class="text-center">操作</th> <th width="180">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="(tr, rowIndex) in allDataList?.list" :key="rowIndex"> <tr v-for="(tr, rowIndex) in allDataList?.list" :key="rowIndex">
<td>{{ tr.name }}</td> <td>{{ tr.name }}</td>
<td>{{ tr.alias }}</td> <td>
<span :title="tr.alias">{{ tr.alias }}</span>
</td>
<td>{{ tr.category == 'gut'?'肠内制剂':'静脉制剂' }}</td> <td>{{ tr.category == 'gut'?'肠内制剂':'静脉制剂' }}</td>
<td v-for="th in ProductCols">{{ (tr as any)[th.alias] || 'NULL' }}</td> <td v-for="th in ProductCols">{{ (tr as any)[th.alias] || 'NULL' }}</td>
@ -105,6 +109,7 @@ function handleSearch(){
<td> <td>
<Space :size="20"> <Space :size="20">
<a @click="editProduct = tr">编辑</a> <a @click="editProduct = tr">编辑</a>
<a @click="productInput = tr">输入指标</a>
<a @click="handleDelete(tr.id)">删除</a> <a @click="handleDelete(tr.id)">删除</a>
</Space> </Space>
</td> </td>
@ -122,6 +127,7 @@ function handleSearch(){
</div> </div>
</div> </div>
<EditModal v-if="!!editProduct" v-model="editProduct" @saved="refresh" /> <EditModal v-if="!!editProduct" v-model="editProduct" @saved="refresh" />
<ProductInputModal v-if="!!productInput" v-model="productInput" />
</div> </div>
</template> </template>
<style lang="scss"></style> <style lang="scss"></style>

View File

@ -0,0 +1,161 @@
<template>
<Modal
:width="640" :open="!saveData" :footer="null" @cancel="handleCancel" :mask-closable="false"
:destroy-on-close="true" title="营养制剂输入指标"
>
<div class="result-table mt-4">
<Spin :spinning="loading">
<table class="table border">
<thead>
<tr>
<th>指标名称</th>
<th>指标Key</th>
<th width="120">输入提示</th>
<th>单位</th>
<th width="120">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(tr, rowIndex) in allDataList?.list" :key="rowIndex">
<td>{{ tr.name }}</td>
<td>{{ tr.key }}</td>
<td>{{ tr.placeholder }}</td>
<td>{{ tr.unit }}</td>
<td>
<Space :size="20">
<a @click="saveData = tr">编辑</a>
<a @click="handleDelete(tr.id)">删除</a>
</Space>
</td>
</tr>
</tbody>
</table>
<div v-if="!allDataList || allDataList?.total == 0" style="padding:30px;">
<Empty description="暂无数据"/>
</div>
</Spin>
<div class="text-center mt-4">
<Button type="primary" @click="handleCreateNew">添加指标</Button>
</div>
</div>
</Modal>
<Modal
:open="!!saveData" :width="640" :footer="null" :destroy-on-close="true" title="营养制剂输入指标"
:mask-closable="false" @cancel="saveData=undefined">
<div>
<Form
@finish="handleSave"
autocomplete="off"
:model="saveData"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 16 }"
>
<div class="py-8 px-10">
<div class="form-item-container">
<Form.Item label="指标名称" name="name"
:rules="[{ required: true, message: '请输入指标名称' }]">
<Input placeholder="请输入指标名称" v-model:value="saveData.name"/>
</Form.Item>
<Form.Item label="指标Key" name="key" :rules="[{ required: true, message: '请输入指标Key' }]">
<Input placeholder="请输入指标Key" v-model:value="saveData.key"/>
</Form.Item>
<Form.Item label="输入提示" name="placeholder">
<Input placeholder="请输入指标提示,留空默认使用:入液量(ml)" v-model:value="saveData.placeholder"/>
</Form.Item>
<Form.Item label="单位" name="unit">
<Input placeholder="请输入指标单位留空默认使用ml" v-model:value="saveData.unit"/>
</Form.Item>
</div>
</div>
<div class="text-center">
<Space :size="20">
<Button type="default" @click="saveData = undefined">取消</Button>
<Button :loading="saveLoading" type="primary" html-type="submit">保存</Button>
</Space>
</div>
</Form>
</div>
</Modal>
</template>
<script lang="ts" setup>
import {Empty, Modal, Space, Spin, Button, Form, Input, message} from "ant-design-vue";
import {onMounted, ref} from "vue";
import {
getProductDataInput,
saveProductDataInput,
deleteProductDataInput,
} from "@/service/api/product.ts";
import useRequest from "@/service/useRequest.ts";
const editData = defineModel<Partial<ProductInfoModel>>();
const saveData = ref<Partial<ProductDataInputModel>>()
const { loading:saveLoading, runAsync, error } = useRequest(saveProductDataInput, {
manual: true
})
const {
data: allDataList,
loading,
run,
refresh
} = useRequest(() => getProductDataInput(editData.value!.id), {manual: true})
function handleCancel() {
editData.value = undefined;
}
function handleCreateNew() {
saveData.value = {
product_id: editData.value!.id,
key: '',
name: '',
placeholder: '',
unit: '',
}
}
function deleteById(id: number) {
deleteProductDataInput(id).then(() => {
message.success('删除成功')
refresh()
})
}
function handleDelete(id: number) {
Modal.confirm({
title: '删除营养制剂数据',
content:'删除此数据后可能导致系统无法正常计算结果或导致系统异常,请确定要删除该数据吗?',
cancelText: '再想想',
okText: '删除',
okType: 'danger',
onOk: () => {
deleteById(id)
}
})
}
function handleSave() {
saveData.value = {
...saveData.value,
created_at: undefined,
updated_at: undefined,
status: undefined,
};
if(!saveData.value.placeholder){
saveData.value.placeholder = '入液量(ml)'
}
if(!saveData.value.unit){
saveData.value.unit = 'ml'
}
runAsync(saveData.value).then(() => {
refresh()
saveData.value = undefined;
})
}
onMounted(() => {
run()
})
</script>
<style scoped lang="scss">
</style>

View File

@ -1,157 +1,164 @@
<template> <template>
<Modal :open="visible" width="600px" @cancel="visible = false" :maskClosable="false" :closable="false" <Modal :open="visible" width="600px" @cancel="visible = false" :maskClosable="false" :closable="false"
title="设置测试数据"> title="设置测试数据">
<div class="setting-container"> <div class="setting-container">
<div class="grid list-container grid-cols-2 gap-4 py-2 max-h-[400px] overflow-auto"> <div class="grid list-container grid-cols-2 gap-4 py-2 max-h-[400px] overflow-auto">
<div class="input-item"> <div class="input-item">
<div class="title">体重</div> <div class="title">体重</div>
<div class="input"> <div class="input">
<input type="number" v-model="commonValues.weight" placeholder="单位(kg)"/> <input type="number" v-model="commonValues.weight" placeholder="单位(kg)"/>
</div> </div>
</div>
<div class="input-item">
<div class="title">24h尿素</div>
<div class="input">
<input type="number" v-model="commonValues.niaosu" placeholder="单位(mmol)"/>
</div>
</div>
</div>
<Tabs>
<TabPane key="gut" tab="肠内制剂">
<div class="grid list-container grid-cols-2 gap-4 py-2 max-h-[400px] overflow-auto">
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='gut')" :key="key">
<div class="title">{{ it.title }}</div>
<div class="input">
<input type="number" v-model="it.value" :placeholder="it.placeholder"/>
<span class="unit">{{ it.unit }}</span>
</div>
</div>
</div>
</TabPane>
<TabPane key="vein" tab="静脉制剂">
<div class="grid list-container grid-cols-2 gap-4 py-2 max-h-[400px] overflow-auto">
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='vein')" :key="key">
<div class="title">{{ it.title }}</div>
<div class="input">
<input type="number" v-model="it.value" :placeholder="it.placeholder"/>
<span class="unit">{{ it.unit }}</span>
</div>
</div>
</div>
</TabPane>
</Tabs>
</div> </div>
<template #footer> <div class="input-item">
<div class="flex justify-center mt-8"> <div class="title">24h尿素</div>
<Button key="submit" type="primary" @click="handleOk">确定</Button> <div class="input">
<input type="number" v-model="commonValues.niaosu" placeholder="单位(mmol)"/>
</div>
</div>
</div>
<Tabs>
<TabPane key="gut" tab="肠内制剂">
<div class="grid list-container grid-cols-2 gap-4 py-2 max-h-[400px] overflow-auto">
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='gut')" :key="key">
<div class="title">{{ it.title }}</div>
<div class="input">
<input type="number" v-model="it.value" :placeholder="it.placeholder"/>
<span class="unit">{{ it.unit }}</span>
</div>
</div> </div>
</template> </div>
</Modal> </TabPane>
<TabPane key="vein" tab="静脉制剂">
<div class="grid list-container grid-cols-2 gap-4 py-2 max-h-[400px] overflow-auto">
<div class="input-item" v-for="(it,key) in settingList.filter(s=>s.type=='vein')" :key="key">
<div class="title">{{ it.title }}</div>
<div class="input">
<input type="number" v-model="it.value" :placeholder="it.placeholder"/>
<span class="unit">{{ it.unit }}</span>
</div>
</div>
</div>
</TabPane>
</Tabs>
</div>
<template #footer>
<div class="flex justify-center mt-8">
<Button key="submit" type="primary" @click="handleOk">确定</Button>
</div>
</template>
</Modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {Modal, Button, Tabs, TabPane} from 'ant-design-vue' import {Modal, Button, Tabs, TabPane} from 'ant-design-vue'
import {defineComponent, onMounted, ref} from "vue"; import {defineComponent, onMounted, ref} from "vue";
import {inputProducts} from "@/pages/result/test/data-input.ts"; // import {inputProducts} from "@/pages/result/test/data-input.ts";
import {getAllProductInput} from "@/service/api/product.ts";
type InputValuesType = { type InputValuesType = {
[key: string]: number; [key: string]: number;
} }
const inputValues = defineModel('inputValues') const inputValues = defineModel('inputValues')
const commonValues = ref({ const commonValues = ref({
weight: '', weight: '',
niaosu: '', niaosu: '',
}) })
const visible = defineModel('visible', {type: Boolean}) const visible = defineModel('visible', {type: Boolean})
defineComponent({ defineComponent({
name: 'InputSetting' name: 'InputSetting'
}) })
const settingList = ref<SettingItem[]>([]) const settingList = ref<SettingItem[]>([])
onMounted(() => { onMounted(() => {
const storeValues = (() => { initInputList().then(() => {
const content = localStorage.getItem('yy_input_setting') console.log('init input setting success')
try { })
if (!content) {
return null;
}
return JSON.parse(content)
} catch (e) {
}
return null;
})();
if (storeValues && Object.keys(storeValues).length > 0) {
inputValues.value = storeValues
commonValues.value = {
weight: storeValues['weight'] && storeValues['weight'] !== 0 ? storeValues['weight'] : '',
niaosu: storeValues['niaosu'] && storeValues['niaosu'] !== 0 ? storeValues['niaosu'] : '',
}
}
const setting: SettingItem[] = []
inputProducts.forEach(it => {
setting.push({
title: it.name,
key: it.key,
value: storeValues && storeValues[it.key] !== 0 ? storeValues[it.key] : '',
placeholder: it.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.unit,
})
if (it.addition) {
setting.push({
title: it.name,
key: it.addition.key,
value: storeValues && storeValues[it.addition.key] !== 0 ? storeValues[it.addition.key] : '',
placeholder: it.addition.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.addition.unit,
})
}
})
const lines:string[] = []
lines.push(`weight体重`)
lines.push(`niaosu24h尿素`)
setting.forEach(it => {
lines.push(`${it.key}${it.title}`)
})
console.log(lines.join("\n"));
settingList.value = setting
}) })
function handleOk() { async function initInputList() {
const values: InputValuesType = { const storeValues = (() => {
weight: Number(commonValues.value.weight || '0'), const content = localStorage.getItem('yy_input_setting')
niaosu: Number(commonValues.value.niaosu || '0'), try {
if (!content) {
return null;
}
return JSON.parse(content)
} catch (e) {
} }
settingList.value.forEach(it => { return null;
values[it.key] = it.value ? Number(it.value) : 0 })();
if (storeValues && Object.keys(storeValues).length > 0) {
inputValues.value = storeValues
commonValues.value = {
weight: storeValues['weight'] && storeValues['weight'] !== 0 ? storeValues['weight'] : '',
niaosu: storeValues['niaosu'] && storeValues['niaosu'] !== 0 ? storeValues['niaosu'] : '',
}
}
const inputProducts = await getAllProductInput();
const setting: SettingItem[] = []
inputProducts.forEach(it => {
setting.push({
title: it.name,
key: it.key,
value: storeValues && storeValues[it.key] !== 0 ? storeValues[it.key] : '',
placeholder: it.placeholder, // + (it.unit?`(${it.unit})`:'')
type: it.type,
unit: it.unit,
}) })
localStorage.setItem('yy_input_setting', JSON.stringify(values)) // if (it.addition) {
visible.value = false // setting.push({
inputValues.value = values; // title: it.name,
// key: it.addition.key,
// value: storeValues && storeValues[it.addition.key] !== 0 ? storeValues[it.addition.key] : '',
// placeholder: it.addition.placeholder, // + (it.unit?`(${it.unit})`:'')
// type: it.type,
// unit: it.addition.unit,
// })
// }
})
const lines: string[] = []
lines.push(`weight体重`)
lines.push(`niaosu24h尿素`)
setting.forEach(it => {
lines.push(`${it.key}${it.title}`)
})
// console.log(lines.join("\n"));
settingList.value = setting
}
function handleOk() {
const values: InputValuesType = {
weight: Number(commonValues.value.weight || '0'),
niaosu: Number(commonValues.value.niaosu || '0'),
}
settingList.value.forEach(it => {
values[it.key] = it.value ? Number(it.value) : 0
})
localStorage.setItem('yy_input_setting', JSON.stringify(values))
visible.value = false
inputValues.value = values;
} }
</script> </script>
<style scoped> <style scoped>
.list-container { .list-container {
margin-right: -4px; margin-right: -4px;
padding-right: 4px; padding-right: 4px;
} }
.setting-container { .setting-container {
.input { .input {
@apply w-full border rounded mt-1 flex items-center; @apply w-full border rounded mt-1 flex items-center;
} }
input { input {
@apply flex-1 outline-0 block ml-2 py-1 mr-1; @apply flex-1 outline-0 block ml-2 py-1 mr-1;
} }
.unit { .unit {
@apply px-2 py-1 bg-gray-200 block h-full text-center; @apply px-2 py-1 bg-gray-200 block h-full text-center;
min-width: 34px; min-width: 34px;
} }
} }
</style> </style>

View File

@ -59,28 +59,28 @@ function handleSearch() {
<div class="data-fields-container"> <div class="data-fields-container">
<PageHeader title="登录账号管理" description="* 超级管理员: 拥有最高权限,可使用全部管理功能。管理员:普通管理权限,不可新建、删除、编辑账号。" /> <PageHeader title="登录账号管理" description="* 超级管理员: 拥有最高权限,可使用全部管理功能。管理员:普通管理权限,不可新建、删除、编辑账号。" />
<div class="search-form"> <div class="search-form">
<Space :size="20"> <div class="grid xl:flex lg:grid-cols-4 md:grid-cols-2 grid-cols-1 w-full gap-4">
<Space class="form-item"> <div class="flex items-center gap-2">
<span>姓名</span> <span>姓名</span>
<Input class="search-item" placeholder="请输入姓名" v-model:value="searchParams.nickname" /> <Input class="search-item flex-1" placeholder="请输入姓名" v-model:value="searchParams.nickname" />
</Space> </div>
<Space class="form-item"> <div class="flex items-center gap-2">
<span>账号</span> <span>账号</span>
<Input class="search-item" placeholder="请输入账号" v-model:value="searchParams.account" /> <Input class="search-item flex-1" placeholder="请输入账号" v-model:value="searchParams.account" />
</Space> </div>
<Space class="form-item"> <div class="flex items-center gap-2">
<span>类型</span> <span>类型</span>
<Select class="search-item" v-model:value="searchParams.role" style="width: 200px;"> <Select class="search-item flex-1" v-model:value="searchParams.role" style="width: 200px;">
<SelectOption v-for="(it, opIndex) in AllRoleList" :key="opIndex" :value="it.value">{{ it.label <SelectOption v-for="(it, opIndex) in AllRoleList" :key="opIndex" :value="it.value">{{ it.label
}} }}
</SelectOption> </SelectOption>
</Select> </Select>
</Space> </div>
<Space class="form-item" :size="15"> <div class="flex items-center gap-2" :size="15">
<Button :icon="h(SearchOutlined)" type="primary" @click="handleSearch">查询</Button> <Button :icon="h(SearchOutlined)" type="primary" @click="handleSearch">查询</Button>
<Button v-if="userInfo?.role == 'root'" :icon="h(PlusOutlined)" class="btn-info" @click="editUser = { id: 0 }">新增</Button> <Button v-if="userInfo?.role == 'root'" :icon="h(PlusOutlined)" class="btn-info" @click="editUser = { id: 0 }">新增</Button>
</Space> </div>
</Space> </div>
</div> </div>
<div class="search-result-table"> <div class="search-result-table">
<div> <div>

View File

@ -70,7 +70,7 @@ function onValuesChange() {
<Form.Item label="密码" name="password" :rules="passwordRules"> <Form.Item label="密码" name="password" :rules="passwordRules">
<Input placeholder="请输入6-12位密码" type="password" v-model:value="userData.password" /> <Input placeholder="请输入6-12位密码" type="password" v-model:value="userData.password" />
<template #extra v-if="editUser?.id"> <template #extra v-if="editUser?.id">
<div>留空不修改密码</div> <div>留空不修改密码</div>
</template> </template>
</Form.Item> </Form.Item>

View File

@ -32,13 +32,13 @@ export const routes:RouteRecordRaw[] = [
component: () => import('./pages/result/index.vue') component: () => import('./pages/result/index.vue')
}, },
// { // {
// path: 'ttt', // path: 'input',
// name: 'ttt', // name: 'input',
// meta: { // meta: {
// title: '输出计算', // title: '输入指标',
// icon:'icon-calculator' // icon:'icon-add'
// }, // },
// component: () => import('./pages/T.vue') // component: () => import('./pages/input/index.vue')
// }, // },
{ {
path: 'product-data', path: 'product-data',

View File

@ -18,6 +18,17 @@ export async function getList(param: ProductSearchParam) {
await sleep(200); await sleep(200);
return await post<DataList<ProductInfoModel>>(`/product/all`, param); return await post<DataList<ProductInfoModel>>(`/product/all`, param);
} }
export async function getProductDataInput(product_id: number) {
await sleep(200);
return await post<DataList<ProductDataInputModel>>(`/input/all`, { product_id });
}
export async function saveProductDataInput(data: Partial<ProductDataInputModel>) {
await sleep(200);
return await post<DataList<ProductDataInputModel>>(`/input/save`, data);
}
export async function deleteProductDataInput(id: number) {
return await post<DataList<ProductDataInputModel>>(`/input/delete`, { id });
}
export function deleteProduct(id: number) { export function deleteProduct(id: number) {
return post(`/product/delete`, { id }) return post(`/product/delete`, { id })
@ -26,3 +37,9 @@ export async function saveProduct(params: Partial<ProductInfoModel>) {
await sleep(200); await sleep(200);
return await post(`/product/save`, params); return await post(`/product/save`, params);
} }
export async function getAllProductInput(){
const result = await post<DataList<ProductDataInputModel>>(`/input/all`)
return result.list;
}

View File

@ -14,58 +14,6 @@ type InputValue = {
} }
} }
/*
{
"weight": 50,
"niaosu": 12,
"ruineng": 10,
"ruidai": 0,
"ruixian": 0,
"ruigao": 0,
"ruisu": 0,
"nengquanli": 0,
"kangquanli": 0,
"kangquangan": 0,
"baipuli": 0,
"ailunduo": 0,
"weiwo": 0,
"jiaweiti": 0,
"yilijia": 0,
"ruiyixi": 0,
"nengquansu": 0,
"ansu": 0,
"quanansu": 0,
"yilijia100": 0,
"shui": 0,
"anjisuan_ruye": 0,
"yilijia100_ruye": 0,
"quanansu_ruye": 0,
"ansu_ruye": 0,
"nengquansu_ruye": 0,
"ruqingdanbailiang": 0,
"ruianji": 0,
"quanyingda": 0,
"likawen": 0,
"lefanming85": 0,
"lefanming114": 0,
"anjisuan": 0,
"litai": 0,
"lineng": 0,
"liwen": 0,
"youwen": 0,
"yingtuolipite20": 0,
"yingtuolipite30": 0,
"putaotangluhuana5": 0,
"putaotang5": 0,
"putaotang10": 0,
"putaotang50": 0,
"luhuana09": 0,
"luhuana10": 0,
"geliefusi": 0,
"luhuajia": 0,
"baidanbai": 0
}
*/
const inputList: InputValue[] = [ const inputList: InputValue[] = [
{name: '体重', key: 'weight',}, {name: '体重', key: 'weight',},
{name: '24h尿素', key: 'niaosu',}, {name: '24h尿素', key: 'niaosu',},

View File

@ -54,7 +54,12 @@
.overflow-auto{ .overflow-auto{
scrollbar-gutter: stable; scrollbar-gutter: stable;
} }
th,td{
text-align: left;
}
.text-center{
text-align: center;
}
[type=reset], [type=reset],
[type=submit], [type=submit],
button, button,
@ -210,12 +215,12 @@ img {
} }
.menu-text{ .menu-text{
display: block; display: block;
@include media-breakpoint-down(lg) { //@include media-breakpoint-down(lg) {
font-size: 12px;; // font-size: 12px;;
} //}
@include media-breakpoint-down(md) { //@include media-breakpoint-down(md) {
display: none; // display: none;
} //}
} }
.search-form { .search-form {
@ -261,11 +266,11 @@ img {
min-width: 0; min-width: 0;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
text-align: left; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
vertical-align: middle; vertical-align: middle;
border-bottom: 1px solid #e8e8ec; border-bottom: 1px solid #e8e8ec;
padding: 15px 16px; padding: 15px 10px;
} }
th { th {

View File

@ -25,6 +25,28 @@ declare type ProductInfoModel = {
updated_at: Date | string; updated_at: Date | string;
status: number; status: number;
} }
interface ProductDataInputModel {
id: number;
/**
* ID(ProductInfoModel.id)
*/
product_id: number;
/**
*
*/
name: string;
/**
*
*/
key: string;
type?: string;
placeholder: string;
unit: string;
created_at: Date | string;
updated_at: Date | string;
status: number;
}
declare type ResultExpression = { declare type ResultExpression = {
id: number; id: number;
@ -63,4 +85,5 @@ interface ResultItem {
title:string; title:string;
key:string; key:string;
value:number; value:number;
} }

View File

@ -16,7 +16,7 @@ const themeConfig = {
export default { export default {
content: [ content: [
'./index.html', './index.html',
'./src/**/*.{mjs,js,ts,jsx,tsx,html,vue}' './src/**/*.{mjs,js,ts,jsx,tsx,html,vue,scss}'
], ],
theme: { theme: {
extend: { extend: {

View File

@ -6,7 +6,7 @@ console.log(
['NODE', 'NODE_ENV', 'npm_execpath', 'OS'].map(key => (process.env[key])) ['NODE', 'NODE_ENV', 'npm_execpath', 'OS'].map(key => (process.env[key]))
) )
const devServer = { const devServer = {
default: 'http://localhost:3001', default: 'http://localhost:23002',
test: 'http://43.136.175.109:50001' test: 'http://43.136.175.109:50001'
} }