初始版本,目前线上可用

This commit is contained in:
2025-11-19 12:49:16 +08:00
commit cb7f1c45e8
178 changed files with 30336 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
<template>
<el-form
:model="formData"
label-width="100px"
inline
style="padding-bottom: 20px">
<el-form-item label="服务分类名称">
<el-input
v-model="formData.name"
placeholder="请输入服务分类名称"></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="formData.remark" placeholder="请输入备注"></el-input>
</el-form-item>
<el-row>
<el-form-item label="分类" style="width: 100%">
<el-tree-select
check-strictly
:check-on-click-node="true"
v-model="formData.parentId"
:props="{ label: 'name', value: 'id' }"
:data="categoryOptions"
:render-after-expand="false"
style="width: 240px" />
</el-form-item>
</el-row>
</el-form>
</template>
<script lang="ts" setup>
import { ref, onMounted } from "vue";
import { ElMessage } from "element-plus";
import api from "@/lib/request";
// 表单数据
const formData = defineModel({
default: {
name: "", // 服务项目名称
remark: "", // 备注
parentId: 0, // 分类ID
},
});
// 分类选项数据
const categoryOptions = ref<{ id: number; name: string }[]>([]);
// 获取分类树并转换为下拉框选项
const loadCategoryTree = async () => {
try {
const res = await api().get("/service-category/list");
if (res.data.list.length) {
categoryOptions.value = [{ id: 0, name: "无" }, ...res.data.list];
} else {
categoryOptions.value = [{ id: 0, name: "无" }];
}
} catch (err) {
ElMessage.error("获取分类树失败");
}
};
// 页面加载时获取分类树
onMounted(() => {
loadCategoryTree();
});
</script>

View File

@@ -0,0 +1,20 @@
<template>
<el-descriptions title="服务项目详情" border style="margin-bottom: 30px">
<el-descriptions-item label="服务项目名称">{{
data.name
}}</el-descriptions-item>
<el-descriptions-item label="数量">{{
data.quantity
}}</el-descriptions-item>
<el-descriptions-item label="单位">{{ data.unit }}</el-descriptions-item>
<el-descriptions-item label="售价">{{ data.price }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ data.remark }}</el-descriptions-item>
<el-descriptions-item label="分类">{{
data.category
}}</el-descriptions-item>
</el-descriptions>
</template>
<script lang="ts" setup>
const data = defineModel<ServiceItemType>({ required: true });
</script>

View File

@@ -0,0 +1,215 @@
<template>
<div>
<baseTableHeader
title="服务分类"
@resetSearch="resetSearch"
@search="search">
<template #content>
<el-form :model="searchForm" :inline="true" label-position="right">
<el-form-item label="分类名称:">
<el-input
v-model="searchForm.name"
placeholder="请输入分类名称"></el-input>
</el-form-item>
<!-- <el-form-item label="分类:">
<el-input
v-model="searchForm.category"
placeholder="请输入分类"></el-input>
</el-form-item> -->
</el-form>
</template>
<template #operateBtns>
<el-button type="primary" @click="add" size="small"
><el-icon> <CirclePlus /> </el-icon>新增</el-button
>
</template>
</baseTableHeader>
<el-card style="margin-top: 8px">
<base-table
:option="tableOption"
ref="table"
style="width: 100%"
:tree-props="{ children: 'children' }"
row-key="id"
:indent="30"
:showPagination="false"
@addConfim="addConfim"
@editConfim="editConfim">
<template #colunm>
<el-table-column prop="name" label="服务分类名称" />
<el-table-column prop="remark" label="备注" align="center" />
<el-table-column
#default="{ row }"
label="操作"
align="center"
fixed="right"
width="250">
<!-- <el-button size="small" type="primary" @click="examine(row)"
>查看</el-button
> -->
<el-button size="small" type="warning" @click="update(row)"
>修改</el-button
>
<el-button size="small" type="danger" @click="deleteData(row)"
>删除</el-button
>
</el-table-column>
</template>
</base-table>
<base-curd-dialog
v-model="pageVisibleState.show2LevelPage.value"
:title="pageVisibleState.dialogTitle.value"
width="50%"
:before-close="handleDialogClose"
@addConfim="addConfim"
@editConfim="editConfim"
@closeConfirm="handleDialogClose"
:showPageType="pageVisibleState.showPageType">
<template #content>
<addOrEdit
:executeType="pageVisibleState.executeType.value"
v-model="currentServiceItem"
v-if="
pageVisibleState.showPageType.edit ||
pageVisibleState.showPageType.add
"></addOrEdit>
<serviceItemView
v-if="pageVisibleState.showPageType.view"
v-model="currentServiceItem"></serviceItemView>
</template>
</base-curd-dialog>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, onMounted, ref, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { resetParams } from "@/util/globalMethods";
import addOrEdit from "./page/addOrEdit.vue";
import serviceItemView from "./page/view.vue";
import pageVisible from "@/components/curdDialog/pageVisibleState";
import api from "@/lib/request";
import { tableOptionType } from "@/types/table";
const pageVisibleState = new pageVisible({
add: "新增服务项目",
edit: "服务项目编辑",
view: "服务项目查看",
});
const searchForm = reactive({
name: "",
category: 0,
});
let currentServiceItem = ref<ServiceItemType>({
name: "",
remark: "",
parentId: 0,
});
watch(
() => pageVisibleState.show2LevelPage,
(newVal) => {
if (newVal.value === false) {
resetServiceItem();
}
},
{
deep: true,
}
);
let table = ref();
let tableOption = ref<tableOptionType>({
url: "/service-category/list",
searchUrl: "/service-category/query",
searchParams: searchForm,
executeType: "list",
});
function add() {
pageVisibleState.show2LevelPage.value = true;
pageVisibleState.showPageType.add = true;
}
function examine(row: ServiceItemType) {
currentServiceItem.value = row;
pageVisibleState.show2LevelPage.value = true;
pageVisibleState.showPageType.view = true;
}
function update(row: ServiceItemType) {
currentServiceItem.value = { ...row };
pageVisibleState.show2LevelPage.value = true;
pageVisibleState.showPageType.edit = true;
}
async function deleteData(row: ServiceItemType) {
await ElMessageBox.confirm("确定要删除该服务分类吗?", {
type: "error",
});
let respone = await api().get("/service-category/delete?id=" + row.id);
if (respone.code === 200) {
ElMessage.success("服务项目删除成功!");
table.value.methods.setDataType("list");
} else {
ElMessage.error(respone.msg);
}
}
function search() {
table.value.methods.setDataType("search");
}
function resetSearch() {
resetParams(searchForm);
table.value.methods.setDataType("list");
ElMessage.success("重置成功!");
}
function handleDialogClose() {
pageVisibleState.show2LevelPage.value = false;
}
async function addConfim() {
await ElMessageBox.confirm("确定新增该分类吗?", "提示", {
type: "warning",
});
let res = await api().post("/service-category/add", currentServiceItem.value);
if (res.code === 200) {
ElMessage.success("添加成功");
pageVisibleState.show2LevelPage.value = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(res.msg);
}
}
async function editConfim() {
ElMessageBox.confirm("确认修改该条信息吗?", "提示", {
type: "warning",
}).then(async () => {
let respone = await api().post(
"/service-category/update",
currentServiceItem.value
);
if (respone.code == 200) {
ElMessage.success("修改成功!");
pageVisibleState.show2LevelPage.value = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(respone.msg);
}
});
}
function resetServiceItem() {
currentServiceItem.value = {
name: "",
quantity: 0,
category: 0,
unit: "",
price: 0,
remark: "",
};
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,57 @@
<template>
<el-form
:model="formData"
label-width="100px"
inline
style="padding-bottom: 20px">
<el-form-item label="服务项目名称">
<el-input
v-model="formData.name"
placeholder="请输入服务项目名称"></el-input>
</el-form-item>
<el-form-item label="单位">
<el-input v-model="formData.unit" placeholder="请输入单位"></el-input>
</el-form-item>
<el-form-item label="售价">
<el-input v-model="formData.price" placeholder="请输入售价"></el-input>
</el-form-item>
<el-form-item label="数量" v-if="props.type === '手工录入服务'">
<el-input v-model="formData.quantity" placeholder="请输入数量"></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="formData.remark" placeholder="请输入备注"></el-input>
</el-form-item>
<el-row v-if="props.type !== '手工录入服务'">
<el-form-item label="分类" style="width: 100%">
<serviceSelect v-model="formData.parentId"></serviceSelect>
</el-form-item>
</el-row>
</el-form>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } from "vue";
import { ElMessage } from "element-plus";
import api from "@/lib/request";
let props = defineProps<{
type: "手工录入服务";
}>();
// 表单数据
const formData = defineModel({
default: {
name: "", // 服务项目名称
quantity: 1, // 数量
unit: "", // 单位
price: 0, // 售价
remark: "", // 备注
parentId: 0, // 分类ID
},
});
// 分类选项数据
const categoryOptions = ref<{ id: number; name: string }[]>([]);
// 页面加载时获取分类树
onMounted(() => {});
</script>

View File

@@ -0,0 +1,20 @@
<template>
<el-descriptions title="服务项目详情" border style="margin-bottom: 30px">
<el-descriptions-item label="服务项目名称">{{
data.name
}}</el-descriptions-item>
<el-descriptions-item label="数量">{{
data.quantity
}}</el-descriptions-item>
<el-descriptions-item label="单位">{{ data.unit }}</el-descriptions-item>
<el-descriptions-item label="售价">{{ data.price }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ data.remark }}</el-descriptions-item>
<el-descriptions-item label="分类">{{
data.category
}}</el-descriptions-item>
</el-descriptions>
</template>
<script lang="ts" setup>
const data = defineModel<ServiceItemType>({ required: true });
</script>

View File

@@ -0,0 +1,247 @@
<template>
<div>
<baseTableHeader
title="服务项目"
@resetSearch="resetSearch"
@search="search">
<template #content>
<el-form :model="searchForm" :inline="true" label-position="right">
<el-form-item label="服务项目名称:">
<el-input
v-model="searchForm.name"
placeholder="请输入服务项目名称"></el-input>
</el-form-item>
<el-form-item label="分类:">
<serviceSelect v-model="searchForm.category"></serviceSelect>
</el-form-item>
</el-form>
</template>
<template #operateBtns>
<el-button type="primary" @click="add" size="small"
><el-icon> <CirclePlus /> </el-icon>新增</el-button
>
</template>
</baseTableHeader>
<el-card style="margin-top: 8px">
<base-table
:option="tableOption"
ref="table"
style="width: 100%"
border
@addConfim="addConfim"
@editConfim="editConfim">
<template #colunm>
<el-table-column
type="index"
label="序号"
width="80"
align="center"></el-table-column>
<el-table-column prop="name" label="服务项目名称" align="center" />
<!-- <el-table-column
prop="quantity"
label="数量"
align="center"
width="80" /> -->
<el-table-column prop="unit" label="单位" align="center" width="80" />
<el-table-column
prop="price"
label="售价"
align="center"
width="120" />
<el-table-column prop="remark" label="备注" align="center" />
<el-table-column prop="parentId" label="分类" align="center">
<template #default="{ row }">
{{
serviceCaregoryOptions.find((item) => item.id === row.parentId)
?.name
}}
</template>
</el-table-column>
<el-table-column
#default="{ row }"
label="操作"
align="center"
fixed="right"
width="250">
<el-button size="small" type="primary" @click="examine(row)"
>查看</el-button
>
<el-button size="small" type="warning" @click="update(row)"
>修改</el-button
>
<el-button size="small" type="danger" @click="deleteData(row)"
>删除</el-button
>
</el-table-column>
</template>
</base-table>
<base-curd-dialog
v-model="pageVisibleState.show2LevelPage.value"
:title="pageVisibleState.dialogTitle.value"
width="50%"
:before-close="handleDialogClose"
@addConfim="addConfim"
@editConfim="editConfim"
@closeConfirm="handleDialogClose"
:showPageType="pageVisibleState.showPageType">
<template #content>
<addOrEdit
:executeType="pageVisibleState.executeType.value"
v-model="currentServiceItem"
v-if="
pageVisibleState.showPageType.edit ||
pageVisibleState.showPageType.add
"></addOrEdit>
<serviceItemView
v-if="pageVisibleState.showPageType.view"
v-model="currentServiceItem"></serviceItemView>
</template>
</base-curd-dialog>
</el-card>
</div>
</template>
<script lang="ts" setup>
import { reactive, onMounted, ref, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { resetParams } from "@/util/globalMethods";
import addOrEdit from "./page/addOrEdit.vue";
import serviceItemView from "./page/view.vue";
import pageVisible from "@/components/curdDialog/pageVisibleState";
import serviceSelect from "@/components/serviceSelect/serviceSelect.vue";
import api from "@/lib/request";
import { tableOptionType } from "@/types/table";
const pageVisibleState = new pageVisible({
add: "新增服务项目",
edit: "服务项目编辑",
view: "服务项目查看",
});
const searchForm = reactive({
name: "",
category: 0,
});
let currentServiceItem = ref<ServiceItemType>({
name: "",
quantity: 0,
category: 0,
unit: "",
price: 0,
remark: "",
});
const serviceCaregoryOptions = ref<{ id: number; name: string }[]>([]);
onMounted(async () => {
const res = await api().get("/service-category/list");
serviceCaregoryOptions.value = [{ id: 0, name: "无" }, ...res.data.list];
});
watch(
() => pageVisibleState.show2LevelPage,
(newVal) => {
if (newVal.value === false) {
resetServiceItem();
}
},
{
deep: true,
}
);
let table = ref();
let tableOption = ref<tableOptionType>({
url: "/service-item/list",
searchUrl: "/service-item/query",
searchParams: searchForm,
executeType: "list",
});
function add() {
pageVisibleState.show2LevelPage.value = true;
pageVisibleState.showPageType.add = true;
}
function examine(row: ServiceItemType) {
currentServiceItem.value = row;
pageVisibleState.show2LevelPage.value = true;
pageVisibleState.showPageType.view = true;
}
function update(row: ServiceItemType) {
currentServiceItem.value = { ...row };
pageVisibleState.show2LevelPage.value = true;
pageVisibleState.showPageType.edit = true;
}
async function deleteData(row: ServiceItemType) {
await ElMessageBox.confirm("确定要删除该服务项目吗?", {
type: "error",
});
let respone = await api().get("/service-item/delete?id=" + row.id);
if (respone.code === 200) {
ElMessage.success("服务项目删除成功!");
table.value.methods.setDataType("list");
} else {
ElMessage.error(respone.msg);
}
}
function search() {
table.value.methods.setDataType("search");
}
function resetSearch() {
resetParams(searchForm);
table.value.methods.setDataType("list");
ElMessage.success("重置成功!");
}
function handleDialogClose() {
pageVisibleState.show2LevelPage.value = false;
}
async function addConfim() {
await ElMessageBox.confirm("确定新增该条信息吗?", "提示", {
type: "warning",
});
let res = await api().post("/service-item/add", currentServiceItem.value);
if (res.code === 200) {
ElMessage.success("添加成功");
pageVisibleState.show2LevelPage.value = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(res.msg);
}
}
async function editConfim() {
ElMessageBox.confirm("确认修改该条信息吗?", "提示", {
type: "warning",
}).then(async () => {
let respone = await api().post(
"/service-item/update",
currentServiceItem.value
);
if (respone.code == 200) {
ElMessage.success("修改成功!");
pageVisibleState.show2LevelPage.value = false;
table.value.methods.setDataType("list");
} else {
ElMessage.error(respone.msg);
}
});
}
function resetServiceItem() {
currentServiceItem.value = {
name: "",
quantity: 0,
category: 0,
unit: "",
price: 0,
remark: "",
};
}
</script>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,20 @@
<template>
<div>
<el-tabs type="border-card">
<el-tab-pane>
<template #label>服务项目</template>
<serviceItemList></serviceItemList>
</el-tab-pane>
<el-tab-pane>
<template #label> 服务分类 </template>
<serviceCategory> </serviceCategory>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script lang="ts" setup>
import serviceItemList from "./serviceItem/serviceItemList.vue";
import serviceCategory from "./serviceCategory/serviceCategory.vue";
</script>
<style lang="scss" scoped></style>