添加产品(药品)数据(修改数据存储模式);修复useRequest使用
This commit is contained in:
parent
f57daee407
commit
a740a36953
@ -16,7 +16,7 @@ const themeConfig = {
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<PageLoading :class="{ hideLoading: store.userInit }" />
|
||||
<Login v-if="store.userInit && (!store.userInfo || store.userInfo.uid < 1)" />
|
||||
<Login v-if="store.userInit && (!store.userInfo || store.userInfo.id < 1)" />
|
||||
<template v-if="store.userInit">
|
||||
<ConfigProvider :theme="themeConfig">
|
||||
<router-view />
|
||||
|
@ -26,4 +26,15 @@
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-modal {
|
||||
.ant-btn-dangerous {
|
||||
background-color: hsl(359, 100%, 60%);
|
||||
color: white !important;
|
||||
|
||||
&:hover {
|
||||
background-color: hsl(359, 100%, 70%);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ export enum RoleEnum {
|
||||
// common user
|
||||
USER = 'user',
|
||||
}
|
||||
|
||||
export const RoleList = [
|
||||
{ label: '超级管理员', value: RoleEnum.ROOT },
|
||||
{ label: '管理员', value: RoleEnum.ADMIN },
|
||||
@ -14,4 +15,17 @@ export const AllRoleList = [
|
||||
|
||||
{ label: '全部', value: '' },
|
||||
...RoleList
|
||||
]
|
||||
|
||||
export enum ProductCategoryEnum {
|
||||
GUT = 'gut',
|
||||
VEIN = 'vein'
|
||||
}
|
||||
export const ProductCategoryList = [
|
||||
{ label: '肠内制剂', value: ProductCategoryEnum.GUT },
|
||||
{ label: '静脉制剂', value: ProductCategoryEnum.VEIN }
|
||||
]
|
||||
export const AllProductCategoryList = [
|
||||
{ label: '全部', value: '' },
|
||||
...ProductCategoryList
|
||||
]
|
@ -4,12 +4,17 @@ import { useUserStore } from "../service/user-store.ts";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
import { AppConfig } from "../app-config.ts";
|
||||
import { Dropdown, Menu, MenuItem, Button } from "ant-design-vue";
|
||||
import { DownOutlined } from "@ant-design/icons-vue"
|
||||
import { Dropdown, Menu, MenuItem, Button, Modal, Form, Input, message } from "ant-design-vue";
|
||||
import { CaretDownOutlined } from "@ant-design/icons-vue"
|
||||
import { MenuInfo } from "ant-design-vue/es/menu/src/interface";
|
||||
// 获取用户数据
|
||||
const store = useUserStore()
|
||||
const showLogo = ref(false)
|
||||
const showUpdateModal = ref(false)
|
||||
const modifyLoading = ref(false)
|
||||
|
||||
|
||||
|
||||
// 获取当前用户能够访问的菜单
|
||||
const currentMenus = computed(() => {
|
||||
// 判断是否有登录数据
|
||||
@ -18,14 +23,45 @@ const currentMenus = computed(() => {
|
||||
return !s.meta || !s.meta['role'] || store.userInfo?.role == s.meta.role;
|
||||
})
|
||||
})
|
||||
|
||||
const handleMenuClick = ({ key }: MenuInfo) => {
|
||||
console.log('click menu', key)
|
||||
if (key == 'logout') {
|
||||
store.logout()
|
||||
} else if (key == 'logout') {
|
||||
|
||||
} else if (key == 'modifyPassword') {
|
||||
showUpdateModal.value = true
|
||||
}
|
||||
}
|
||||
const editData = ref<ModifyUserPassword>({
|
||||
origin_password: '',
|
||||
new_password: '',
|
||||
repeat_password: ''
|
||||
})
|
||||
const handleUpdatePassword = () => {
|
||||
modifyLoading.value = true
|
||||
|
||||
store.updatePassword(editData.value).then(() => {
|
||||
message.success('修改登录密码成功')
|
||||
}).finally(() => {
|
||||
showUpdateModal.value = false
|
||||
})
|
||||
}
|
||||
const validateConfirmPass = async (_rule: any, value: string) => {
|
||||
if (value === '') {
|
||||
return Promise.reject('请再次输入新密码确认!');
|
||||
} else if (value !== editData.value.new_password) {
|
||||
return Promise.reject("两次输入的密码不一致");
|
||||
} else if (value === editData.value.origin_password) {
|
||||
return Promise.reject("新密码不能与原始密码相同");
|
||||
}
|
||||
return Promise.resolve();
|
||||
};
|
||||
function handleHideModal() {
|
||||
// 隐藏
|
||||
showUpdateModal.value = false
|
||||
// 清空数据
|
||||
editData.value = { origin_password: '', new_password: '', repeat_password: '' }
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -53,13 +89,13 @@ const handleMenuClick = ({ key }: MenuInfo) => {
|
||||
<Dropdown>
|
||||
<template #overlay>
|
||||
<Menu @click="handleMenuClick">
|
||||
<MenuItem key="modifyPassword">修改资料</MenuItem>
|
||||
<MenuItem key="modifyPassword">修改密码</MenuItem>
|
||||
<MenuItem key="logout">退出登录</MenuItem>
|
||||
</Menu>
|
||||
</template>
|
||||
<Button class="flex item-center">
|
||||
<Button class="flex items-center">
|
||||
<span>{{ store.userInfo?.nickname }}</span>
|
||||
<DownOutlined />
|
||||
<CaretDownOutlined :style="{ fontSize: '12px' }" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
@ -68,6 +104,30 @@ const handleMenuClick = ({ key }: MenuInfo) => {
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
<Modal :width="450" :open="showUpdateModal" title="修改登录密码" :mask-closable="false" :destroy-on-close="true"
|
||||
@cancel="handleHideModal" :footer="null">
|
||||
<Form @finish="handleUpdatePassword" autocomplete="off" :model="editData" :label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 16 }">
|
||||
<div class="py-8">
|
||||
<Form.Item label="原始密码" name="origin_password" :rules="[{ required: true, message: '请输入原始密码' }]">
|
||||
<Input type="password" placeholder="请输入原始密码" v-model:value="editData.origin_password" />
|
||||
</Form.Item>
|
||||
<Form.Item label="新密码" name="new_password"
|
||||
:rules="[{ required: true, message: '请输入新密码' }, { min: 6, max: 12, message: '密码为6-12位长度' }]">
|
||||
<Input type="password" placeholder="请输入新密码" v-model:value="editData.new_password" />
|
||||
</Form.Item>
|
||||
<Form.Item label="确认密码" name="repeat_password" :rules="[{ validator: validateConfirmPass }]">
|
||||
<Input type="password" placeholder="请输入新密码确认" v-model:value="editData.repeat_password" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
<Form.Item class="flex justify-end mb-0">
|
||||
<div class="flex gap-4">
|
||||
<Button @click="handleHideModal">取消</Button>
|
||||
<Button type="primary" :loading="modifyLoading" html-type="submit">确定</Button>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -1,82 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, h } from "vue";
|
||||
import { SearchOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import {
|
||||
Pagination, Select, SelectOption, Input, Button,
|
||||
Space,
|
||||
} from 'ant-design-vue'
|
||||
import PageHeader from '../components/page-header.vue'
|
||||
import { fields, getProductValues } from "../service/data";
|
||||
|
||||
const searchParams = ref({
|
||||
type: '',
|
||||
name: ''
|
||||
})
|
||||
|
||||
const current = ref(2);
|
||||
const pageSize = ref<number>(20);
|
||||
const columns = fields;
|
||||
const allDataList = getProductValues();
|
||||
console.log(allDataList)
|
||||
|
||||
const opts = [
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '能量密度', value: 'power' },
|
||||
{ label: 'Pro(g)', value: 'pro' },
|
||||
{ label: 'Na(g)', value: 'na' },
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<div class="data-fields-container">
|
||||
<PageHeader title="输入指标编辑" description="*输入指标: 作为输入参数进行计算,可对指标进行新增、编辑、删除操作。" />
|
||||
<div class="search-form">
|
||||
<Space :size="20">
|
||||
<Space class="form-item">
|
||||
<span>营养制剂</span>
|
||||
<Input class="search-item" placeholder="请输入营养制剂" v-model:value="searchParams.name" />
|
||||
</Space>
|
||||
<Space class="form-item">
|
||||
<span>类型</span>
|
||||
<Select class="search-item" v-model:value="searchParams.type">
|
||||
<SelectOption v-for="(it, opIndex) in opts" :key="opIndex" :value="it.value">{{ it.label }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</Space>
|
||||
<Space class="form-item" :size="15">
|
||||
<Button :icon="h(SearchOutlined)" type="primary">查询</Button>
|
||||
<Button :icon="h(PlusOutlined)" class="btn-info">新增</Button>
|
||||
</Space>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="search-result-table">
|
||||
<div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>营养制剂</th>
|
||||
<th v-for="th in columns">{{ th.name }}</th>
|
||||
<th width="150">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(tr, rowIndex) in allDataList" :key="rowIndex">
|
||||
<td>{{ tr.product.name }}</td>
|
||||
<td v-for="it in tr.values">{{ it.value }}</td>
|
||||
<td>
|
||||
<Space :size="20">
|
||||
<a>编辑</a>
|
||||
<a>删除</a>
|
||||
</Space>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="data-page">
|
||||
<Pagination v-model:current="current" v-model:page-size="pageSize" :total="50"
|
||||
:show-total="total => `共 ${total} 条`" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss"></style>
|
133
src/pages/product/edit-modal.vue
Normal file
133
src/pages/product/edit-modal.vue
Normal file
@ -0,0 +1,133 @@
|
||||
<script lang="ts" setup>
|
||||
import { defineModel, reactive } from 'vue';
|
||||
import { Modal, Form, Input, Space, Button, Select, SelectOption } from 'ant-design-vue';
|
||||
import useRequest from '@/service/useRequest';
|
||||
import { saveProduct } from '@/service/api/product';
|
||||
|
||||
const editData = defineModel<Partial<ProductInfoModel>>();
|
||||
const currentData = reactive<Partial<ProductInfoModel>>({ ...(editData ? editData.value : {}) });
|
||||
|
||||
defineExpose({})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'saved'): void
|
||||
}>()
|
||||
|
||||
const { loading, runAsync, error } = useRequest(saveProduct, {
|
||||
manual: true
|
||||
})
|
||||
|
||||
function handleSave() {
|
||||
runAsync(currentData).then(() => {
|
||||
editData.value = undefined;
|
||||
emit('saved')
|
||||
})
|
||||
//
|
||||
}
|
||||
function handleCancel() {
|
||||
editData.value = undefined;
|
||||
}
|
||||
function handleFinishError(errorInfo: any) {
|
||||
console.log('handleFinishError', errorInfo)
|
||||
}
|
||||
function onValuesChange() {
|
||||
error.value = undefined
|
||||
}
|
||||
/*
|
||||
[
|
||||
{ id: 1, name: "能量密度", alias: "power" },
|
||||
{ id: 2, name: "蛋白Pro", alias: "protein" },
|
||||
{ id: 3, name: "Glu", alias: "glu" },
|
||||
{ id: 4, name: "Fat", alias: "fat" },
|
||||
{ id: 5, name: "纤维素", alias: "cellulose" },
|
||||
{ id: 6, name: "Na", alias: "na" },
|
||||
{ id: 7, name: "K", alias: "k" },
|
||||
{ id: 8, name: "Ca", alias: "ca" },
|
||||
{ id: 9, name: "P", alias: "p" },
|
||||
{ id: 10, name: "Mg", alias: "mg" },
|
||||
];
|
||||
*/
|
||||
// const DataFields = [
|
||||
// { label: '能量密度', name: 'power',message:'请输入能量密度数据' },
|
||||
// { label: '蛋白Pro', name: 'protein',message:'请输入蛋白Pro数据' },
|
||||
// { label: 'Glu', name: 'glu',message:'请输入Glu数据' },
|
||||
// { label: 'Fat', name: 'fat',message:'请输入Fat数据' },
|
||||
// { label: '纤维素', name: 'cellulose',message:'请输入纤维素数据' },
|
||||
// { label: 'Na', name: 'na',message:'请输入Na数据' },
|
||||
// { label: 'K', name: 'k',message:'请输入K数据' },
|
||||
// { label: 'Ca', name: 'ca',message:'请输入Ca数据' },
|
||||
// { label: 'P', name: 'p',message:'请输入P数据' },
|
||||
// { label: 'Mg', name: 'mg',message:'请输入Mg数据' },
|
||||
// ]
|
||||
</script>
|
||||
<template>
|
||||
<Modal :width="640" :open="true" :footer="null" @cancel="handleCancel" :mask-closable="false"
|
||||
:destroy-on-close="true">
|
||||
<div class="pt-12">
|
||||
<Form @finish="handleSave" @finishFailed="handleFinishError" @validate="onValuesChange" autocomplete="off"
|
||||
:model="currentData" :label-col="{ span: 7 }" :wrapper-col="{ span: 16 }">
|
||||
<div class="form-item-container grid grid-cols-2">
|
||||
<Form.Item label="营养制剂" name="name" :rules="[{ required: true, message: '请输入营养制剂名称' }]">
|
||||
<Input placeholder="请输入营养制剂名称" v-model:value="currentData.name" />
|
||||
</Form.Item>
|
||||
<Form.Item label="别名" name="alias" :rules="[{ required: true, message: '请输入制剂别名' }]">
|
||||
<Input placeholder="请输入别名" v-model:value="currentData.alias" />
|
||||
</Form.Item>
|
||||
<Form.Item label="单位" name="unit" :rules="[{ required: true, message: '请输入制剂单位' }]">
|
||||
<Input placeholder="请输入单位" v-model:value="currentData.unit" />
|
||||
</Form.Item>
|
||||
<Form.Item label="分类" name="category" :rules="[{ required: true, message: '请输入分类' }]">
|
||||
<Select v-model:value="currentData.category" placeholder="请选择制剂分类">
|
||||
<SelectOption value="gut">肠内制剂</SelectOption>
|
||||
<SelectOption value="vein">静脉制剂</SelectOption>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label="能量密度" name="power" :rules="[{ required: true, message: '请输入能量密度' }]">
|
||||
<Input placeholder="请输入能量密度" v-model:value="currentData.power" />
|
||||
</Form.Item>
|
||||
<Form.Item label="蛋白Pro" name="protein" :rules="[{ required: true, message: '请输入蛋白Pro' }]">
|
||||
<Input placeholder="请输入蛋白Pro" v-model:value="currentData.protein" />
|
||||
</Form.Item>
|
||||
<Form.Item label="Glu" name="glu" :rules="[{ required: true, message: '请输入Glu' }]">
|
||||
<Input placeholder="请输入Glu" v-model:value="currentData.glu" />
|
||||
</Form.Item>
|
||||
<Form.Item label="Fat" name="fat" :rules="[{ required: true, message: '请输入Fat' }]">
|
||||
<Input placeholder="请输入Fat" v-model:value="currentData.fat" />
|
||||
</Form.Item>
|
||||
<Form.Item label="纤维素" name="cellulose" :rules="[{ required: true, message: '请输入纤维素' }]">
|
||||
<Input placeholder="请输入纤维素" v-model:value="currentData.cellulose" />
|
||||
</Form.Item>
|
||||
<Form.Item label="Na" name="na" :rules="[{ required: true, message: '请输入Na' }]">
|
||||
<Input placeholder="请输入Na" v-model:value="currentData.na" />
|
||||
</Form.Item>
|
||||
<Form.Item label="K" name="k" :rules="[{ required: true, message: '请输入K' }]">
|
||||
<Input placeholder="请输入K" v-model:value="currentData.k" />
|
||||
</Form.Item>
|
||||
<Form.Item label="Ca" name="ca" :rules="[{ required: true, message: '请输入Ca' }]">
|
||||
<Input placeholder="请输入Ca" v-model:value="currentData.ca" />
|
||||
</Form.Item>
|
||||
<Form.Item label="P" name="p" :rules="[{ required: true, message: '请输入P' }]">
|
||||
<Input placeholder="请输入P" v-model:value="currentData.p" />
|
||||
</Form.Item>
|
||||
<Form.Item label="Mg" name="mg" :rules="[{ required: true, message: '请输入Mg' }]">
|
||||
<Input placeholder="请输入Mg" v-model:value="currentData.mg" />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<!-- <Form.Item v-for="(item,index) in DataFields" :key="index"" :label="item.label" :name="item.name" :rules="[{ required: true, message: item.message }]">
|
||||
<Input :placeholder="item.message" v-model:value="currentData.name" />
|
||||
</Form.Item> -->
|
||||
|
||||
<div v-if="error" class="text-red-500 text-center">
|
||||
{{ error?.message }}
|
||||
</div>
|
||||
<Form.Item class="flex justify-end mt-6 mb-0">
|
||||
<Space :size="20">
|
||||
<Button @click="handleCancel">取消</Button>
|
||||
<Button :loading="loading" html-type="submit" class="btn-info">确定</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
112
src/pages/product/index.vue
Normal file
112
src/pages/product/index.vue
Normal file
@ -0,0 +1,112 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, h } from "vue";
|
||||
import { SearchOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import {
|
||||
Pagination, Select, SelectOption, Input, Button,
|
||||
Space, Empty, Spin,
|
||||
Modal,
|
||||
message
|
||||
} from 'ant-design-vue'
|
||||
import PageHeader from '@/components/page-header.vue'
|
||||
import { AllProductCategoryList } from "@/core/enums";
|
||||
import { ProductCols } from "@/service/api/product";
|
||||
import { getList, deleteProduct } from "@/service/api/product";
|
||||
import useRequest from "@/service/useRequest";
|
||||
import EditModal from "./edit-modal.vue"
|
||||
|
||||
|
||||
const editProduct = ref<Partial<ProductInfoModel>>()
|
||||
const searchParams = ref<ProductSearchParam>({
|
||||
page: 1,
|
||||
limit: 10,
|
||||
category: '',
|
||||
})
|
||||
|
||||
const { data: allDataList, loading, run, refresh } = useRequest(() => getList(searchParams.value))
|
||||
|
||||
function deleteById(id: number) {
|
||||
deleteProduct(id).then(() => {
|
||||
message.success('删除成功')
|
||||
refresh()
|
||||
})
|
||||
}
|
||||
|
||||
function handleDelete(id: number) {
|
||||
Modal.confirm({
|
||||
title: '删除营养制剂数据',
|
||||
content:'删除此数据后可能导致系统无法正常计算结果,请确定要删除该数据吗?',
|
||||
cancelText: '取消',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
onOk: () => {
|
||||
deleteById(id)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="data-fields-container">
|
||||
<PageHeader title="输入指标编辑" description="*输入指标: 作为输入参数进行计算,可对指标进行新增、编辑、删除操作。" />
|
||||
<div class="search-form">
|
||||
<Space :size="20">
|
||||
<Space class="form-item">
|
||||
<span>营养制剂</span>
|
||||
<Input class="search-item" placeholder="请输入营养制剂名称" v-model:value="searchParams.name" />
|
||||
</Space>
|
||||
<Space class="form-item">
|
||||
<span>类型</span>
|
||||
<Select class="search-item w-[120px]" v-model:value="searchParams.category">
|
||||
<SelectOption v-for="(it, opIndex) in AllProductCategoryList" :key="opIndex" :value="it.value">
|
||||
{{ it.label }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</Space>
|
||||
<Space class="form-item" :size="15">
|
||||
<Button :icon="h(SearchOutlined)" type="primary" @click="run">查询</Button>
|
||||
<Button :icon="h(PlusOutlined)" class="btn-info" @click="editProduct = { id: 0 }">新增</Button>
|
||||
</Space>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="search-result-table">
|
||||
<div>
|
||||
|
||||
<Spin :spinning="loading">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>营养制剂</th>
|
||||
<th v-for="th in ProductCols">{{ th.name }}</th>
|
||||
<th width="150">计量单位</th>
|
||||
<th width="150">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(tr, rowIndex) in allDataList?.list" :key="rowIndex">
|
||||
<td>{{ tr.name }}</td>
|
||||
<td v-for="th in ProductCols">{{ (tr as any)[th.alias] || 'NULL' }}</td>
|
||||
|
||||
<td>{{ tr.unit }}</td>
|
||||
<td>
|
||||
<Space :size="20">
|
||||
<a @click="editProduct = 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>
|
||||
<div v-if="allDataList && allDataList?.total > 0" class="data-page">
|
||||
<Pagination v-model:current="searchParams.page" v-model:page-size="searchParams.limit"
|
||||
:total="allDataList.total" :show-total="(total: number) => `共 ${total} 条`" @change="run" />
|
||||
</div>
|
||||
</div>
|
||||
<EditModal v-if="!!editProduct" v-model="editProduct" @saved="refresh" />
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss"></style>
|
@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<p>输出计算</p>
|
||||
<!-- <DataField /> -->
|
||||
<Button @click="showMessage">test</Button>
|
||||
<div>
|
||||
<Demo />
|
||||
</div>
|
||||
<div>
|
||||
<Form @finish="handleSave" @finishFailed="handleFinishError" autocomplete="off" :model="userData"
|
||||
:label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
|
||||
<Form.Item label="用户名" name="nickname" :rules="[{ required: true, message: '请输入姓名' }]">
|
||||
<Input placeholder="请输入姓名" v-model:value="userData.nickname" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="账号" name="account" :rules="[{ required: true, message: '请输入手机号或邮箱' }]">
|
||||
<Input placeholder="请输入手机号或邮箱" v-model:value="userData.account" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="密码" name="password" :rules="passwordRules">
|
||||
<Input placeholder="请输入6-12位密码" type="password" v-model:value="userData.password" />
|
||||
<div>{{ userData?.id ? '如果不需要修改,请不要填写' : '' }}</div>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="角色" name="role" :rules="[{ required: true, message: '请选择用户角色' }]">
|
||||
<Select placeholder="请选择" style="width: 100%;" v-model:value="userData.role">
|
||||
<SelectOption v-for="(it, opIndex) in RoleList" :key="opIndex" :value="it.value">{{ it.label }}
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item class="flex justify-end mt-10 mb-0">
|
||||
<Space :size="20">
|
||||
<Button html-type="submit">确定</Button>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, computed } from 'vue'
|
||||
import { Form, Input, Button,Select,SelectOption,Space } from "ant-design-vue"
|
||||
import { RoleList } from '@/core/role';
|
||||
// import DataField from "@/components/data-fields/index.vue"
|
||||
// import Button from "../components/button/button.vue";
|
||||
import { message } from "../components/message";
|
||||
|
||||
import Demo from './result/demo.vue'
|
||||
|
||||
const userData = reactive<Partial<UserInfo>>({});
|
||||
|
||||
|
||||
const passwordRules = computed(() => {
|
||||
return userData?.id ? [
|
||||
{ min: 6, max: 12, message: '请输入6-12位密码' }
|
||||
] : [
|
||||
{ required: true, message: '请输入6-12位密码' },
|
||||
{ min: 6, max: 12, message: '请输入6-12位密码' }
|
||||
]
|
||||
})
|
||||
|
||||
function handleSave() {
|
||||
console.log(userData)
|
||||
if (userData) {
|
||||
// run(userData)
|
||||
}
|
||||
//
|
||||
}
|
||||
function handleFinishError(errorInfo: any) {
|
||||
console.log('handleFinishError', errorInfo)
|
||||
}
|
||||
const showMessage = () => {
|
||||
message.show(
|
||||
'This notification does not automatically close, and you need to click the close button to close.',
|
||||
'Notification title',
|
||||
0
|
||||
)
|
||||
}
|
||||
</script>
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<Form v-model="formState" name="basic" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off"
|
||||
@finish="onFinish" @finishFailed="onFinishFailed">
|
||||
<Form.Item label="Username" name="username"
|
||||
:rules="[{ required: true, message: 'Please input your username!' }]">
|
||||
<Input v-model:value="formState.username" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Password" name="password"
|
||||
:rules="[{ required: true, message: 'Please input your password!' }]">
|
||||
<InputPassword v-model:value="formState.password" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="remember" :wrapper-col="{ offset: 8, span: 16 }">
|
||||
<Checkbox v-model:checked="formState.remember">Remember me</Checkbox>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item :wrapper-col="{ offset: 8, span: 16 }">
|
||||
<Button type="primary" html-type="submit">Submit</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue';
|
||||
import { Form, Input, Checkbox, Button, InputPassword } from 'ant-design-vue'
|
||||
|
||||
interface FormState {
|
||||
username: string;
|
||||
password: string;
|
||||
remember: boolean;
|
||||
}
|
||||
|
||||
const formState = reactive<FormState>({
|
||||
username: '',
|
||||
password: '',
|
||||
remember: true,
|
||||
});
|
||||
const onFinish = (values: any) => {
|
||||
console.log('Success:', values);
|
||||
};
|
||||
|
||||
const onFinishFailed = (errorInfo: any) => {
|
||||
console.log('Failed:', errorInfo);
|
||||
};
|
||||
</script>
|
18
src/pages/result/index.vue
Normal file
18
src/pages/result/index.vue
Normal file
@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<p>输出计算</p>
|
||||
<!-- <DataField /> -->
|
||||
<Button @click="showMessage">test</Button>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
// import DataField from "@/components/data-fields/index.vue"
|
||||
import Button from "@/components/button/button.vue";
|
||||
import { message } from "@/components/message";
|
||||
|
||||
const showMessage = () => {
|
||||
message.show(
|
||||
'This notification does not automatically close, and you need to click the close button to close.',
|
||||
'Notification title',
|
||||
0
|
||||
)
|
||||
}
|
||||
</script>
|
@ -5,10 +5,12 @@ import {
|
||||
Pagination, Select, SelectOption, Input, Button, Space, Empty, Spin,
|
||||
Modal, message
|
||||
} from 'ant-design-vue'
|
||||
import { RoleEnum, AllRoleList } from '@/core/role'
|
||||
|
||||
import { RoleEnum, AllRoleList } from '@/core/enums.ts'
|
||||
import { columns, getList, deleteUser } from "@/service/api/user";
|
||||
import PageHeader from '@/components/page-header.vue'
|
||||
import useRequest from "@/service/useRequest";
|
||||
|
||||
import EditModal from './modal.vue'
|
||||
|
||||
const editUser = ref<Partial<UserInfo>>()
|
||||
@ -18,15 +20,10 @@ const searchParams = ref<UserSearchParam>({
|
||||
role: ''
|
||||
})
|
||||
|
||||
const { data: allDataList, loading, run, refresh } = useRequest(() => getList(searchParams.value), {
|
||||
refreshDeps: [searchParams]
|
||||
})
|
||||
const { data: allDataList, loading, run, refresh } = useRequest(() => getList(searchParams.value))
|
||||
|
||||
|
||||
|
||||
watch(searchParams, run, { deep: true })
|
||||
function search() {
|
||||
searchParams.value.page = 1;
|
||||
run()
|
||||
}
|
||||
function deleteUserById(id: number) {
|
||||
deleteUser(id).then(() => {
|
||||
message.success('删除成功')
|
||||
@ -72,10 +69,8 @@ function handleDelete(id: number) {
|
||||
</Select>
|
||||
</Space>
|
||||
<Space class="form-item" :size="15">
|
||||
<Button :icon="h(SearchOutlined)" type="primary"
|
||||
@click="search()">查询</Button>
|
||||
<Button :icon="h(PlusOutlined)" class="btn-info"
|
||||
@click="editUser = { id: 0 }">新增</Button>
|
||||
<Button :icon="h(SearchOutlined)" type="primary" @click="run">查询</Button>
|
||||
<Button :icon="h(PlusOutlined)" class="btn-info" @click="editUser = { id: 0 }">新增</Button>
|
||||
</Space>
|
||||
</Space>
|
||||
</div>
|
||||
@ -111,7 +106,7 @@ function handleDelete(id: number) {
|
||||
|
||||
<div v-if="allDataList && allDataList?.total > 0" class="data-page">
|
||||
<Pagination v-model:current="searchParams.page" v-model:page-size="searchParams.limit"
|
||||
:total="allDataList.total" :show-total="(total: number) => `共 ${total} 条`" />
|
||||
:total="allDataList.total" :show-total="(total: number) => `共 ${total} 条`" @change="run" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -119,12 +114,5 @@ function handleDelete(id: number) {
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.ant-btn-dangerous {
|
||||
background-color: hsl(359, 100%, 60%);
|
||||
color: white !important;
|
||||
|
||||
&:hover {
|
||||
background-color: hsl(359, 100%, 70%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -3,7 +3,7 @@ import { computed, defineModel, reactive } from 'vue';
|
||||
import { Modal, Form, Input, Select, SelectOption, Space, Button } from 'ant-design-vue';
|
||||
import { md5 } from 'js-md5';
|
||||
|
||||
import { RoleList } from '@/core/role';
|
||||
import { RoleList } from '@/core/enums';
|
||||
import useRequest from '@/service/useRequest';
|
||||
import { saveUser } from '@/service/api/user';
|
||||
|
||||
|
@ -29,16 +29,16 @@ export const routes:RouteRecordRaw[] = [
|
||||
title: '输出计算',
|
||||
icon:'icon-calculator'
|
||||
},
|
||||
component: () => import('./pages/result.vue')
|
||||
component: () => import('./pages/result/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'data',
|
||||
name: 'data',
|
||||
path: 'product-data',
|
||||
name: 'product',
|
||||
meta: {
|
||||
title: '数据管理',
|
||||
icon:'icon-input'
|
||||
},
|
||||
component: () => import('./pages/datas.vue')
|
||||
component: () => import('./pages/product/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'user',
|
||||
|
28
src/service/api/product.ts
Normal file
28
src/service/api/product.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { sleep } from "@/core/sleep";
|
||||
import { post } from "./request";
|
||||
|
||||
export const ProductCols = [
|
||||
{ id: 1, name: "能量密度", alias: "power" },
|
||||
{ id: 2, name: "蛋白Pro", alias: "protein" },
|
||||
{ id: 3, name: "Glu", alias: "glu" },
|
||||
{ id: 4, name: "Fat", alias: "fat" },
|
||||
{ id: 5, name: "纤维素", alias: "cellulose" },
|
||||
{ id: 6, name: "Na", alias: "na" },
|
||||
{ id: 7, name: "K", alias: "k" },
|
||||
{ id: 8, name: "Ca", alias: "ca" },
|
||||
{ id: 9, name: "P", alias: "p" },
|
||||
{ id: 10, name: "Mg", alias: "mg" },
|
||||
];
|
||||
|
||||
export async function getList(param: ProductSearchParam) {
|
||||
await sleep(200);
|
||||
return await post<DataList<ProductInfoModel>>(`/product/all`, param);
|
||||
}
|
||||
|
||||
export function deleteProduct(id: number) {
|
||||
return post(`/product/delete`, { id })
|
||||
}
|
||||
export async function saveProduct(params: Partial<ProductInfoModel>) {
|
||||
await sleep(200);
|
||||
return await post(`/product/save`, params);
|
||||
}
|
@ -6,6 +6,10 @@ export async function saveUser(params: Partial<UserInfo>) {
|
||||
await sleep(200);
|
||||
return await post<UserInfo>(`/user/save`, params);
|
||||
}
|
||||
export async function updateUserPassword(params: ModifyUserPassword) {
|
||||
await sleep(200);
|
||||
return await post<UserInfo>(`/user/modify_password`, params);
|
||||
}
|
||||
|
||||
export function userLogin(params: LoginModel) {
|
||||
return post<{ token: string; user: UserInfo }>(`/user/login`, params);
|
||||
|
@ -25,6 +25,7 @@ export const fields: BaseModel[] = [
|
||||
{ id: 8, name: "Ca", alias: "ca" },
|
||||
{ id: 9, name: "P", alias: "p" },
|
||||
{ id: 10, name: "Mg", alias: "mg" },
|
||||
{ id: 10, name: "计量单位", alias: "unit" },
|
||||
];
|
||||
export const products: BaseModel[] = [
|
||||
{ id: 1, name: "爱伦多", alias: "ailunduo" },
|
||||
@ -211,6 +212,7 @@ export function getProductValues() {
|
||||
product,
|
||||
values: values[product.id],
|
||||
}));
|
||||
console.log(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { defineStore } from "pinia"
|
||||
import { onMounted, ref } from "vue"
|
||||
import { md5 } from "js-md5";
|
||||
import { sleep } from "@/core/sleep.ts";
|
||||
import { userLogin, getInfo } from "./api/user";
|
||||
import { userLogin, getInfo,saveUser,updateUserPassword } from "./api/user";
|
||||
|
||||
import { BizError } from "@/types/core.ts";
|
||||
|
||||
@ -37,8 +37,14 @@ export const useUserStore = defineStore('counter', () => {
|
||||
userInfo.value = undefined;
|
||||
}
|
||||
// 更新用户信息
|
||||
const updateUserInfo = async (info: UserInfo) => {
|
||||
userInfo.value = info
|
||||
const updateUserInfo = async (info: Partial<UserInfo>) => {
|
||||
await saveUser(info)
|
||||
await getUserInfo()
|
||||
}
|
||||
const updatePassword = async (data: ModifyUserPassword) => {
|
||||
if(!userInfo.value) throw new BizError('please login',401)
|
||||
data.id = userInfo.value.id;
|
||||
await updateUserPassword(data)
|
||||
}
|
||||
// 获取用户信息
|
||||
const getUserInfo = async () => {
|
||||
@ -69,6 +75,7 @@ export const useUserStore = defineStore('counter', () => {
|
||||
login,
|
||||
logout,
|
||||
updateUserInfo,
|
||||
getUserInfo
|
||||
getUserInfo,
|
||||
updatePassword
|
||||
}
|
||||
})
|
||||
|
27
src/types/product.d.ts
vendored
Normal file
27
src/types/product.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
declare type ProductSearchParam = {
|
||||
page: number;
|
||||
limit: number;
|
||||
name?: string;
|
||||
category?: string;
|
||||
}
|
||||
|
||||
declare type ProductInfoModel = {
|
||||
id: number;
|
||||
name: string;
|
||||
alias: string;
|
||||
category: string;
|
||||
unit: string;
|
||||
power: number;
|
||||
protein: number;
|
||||
glu: number;
|
||||
fat: number;
|
||||
cellulose: number;
|
||||
na: number;
|
||||
k: number;
|
||||
ca: number;
|
||||
p: number;
|
||||
mg: number;
|
||||
created_at: Date | string;
|
||||
updated_at: Date | string;
|
||||
status: number;
|
||||
}
|
10
src/types/user.d.ts
vendored
10
src/types/user.d.ts
vendored
@ -1,9 +1,9 @@
|
||||
declare type LoginModel = {
|
||||
declare interface LoginModel {
|
||||
account: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
declare type UserSearchParam = {
|
||||
declare interface UserSearchParam {
|
||||
page: number;
|
||||
limit: number;
|
||||
nickname?: string;
|
||||
@ -20,4 +20,10 @@ declare interface UserInfo {
|
||||
last_login: string;
|
||||
updated_at: string;
|
||||
status: number;
|
||||
}
|
||||
declare interface ModifyUserPassword {
|
||||
id?: number;
|
||||
origin_password: string;
|
||||
new_password: string;
|
||||
repeat_password: string;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user