This commit is contained in:
Leo_Ding 2025-10-17 19:23:52 +08:00
parent 65caeb0f1a
commit acf29dd294
28 changed files with 2150 additions and 588 deletions

107
package-lock.json generated
View File

@ -12,6 +12,7 @@
"@ant-design/colors": "^7.0.0",
"@ant-design/icons-vue": "^6.1.0",
"@icon-park/vue-next": "^1.4.2",
"@jiaminghi/data-view": "^2.10.0",
"@tinymce/tinymce-vue": "^5.1.0",
"ant-design-vue": "^4.0.1",
"axios": "^1.4.0",
@ -904,6 +905,62 @@
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jiaminghi/bezier-curve": {
"version": "0.0.9",
"resolved": "https://registry.npmmirror.com/@jiaminghi/bezier-curve/-/bezier-curve-0.0.9.tgz",
"integrity": "sha512-u9xJPOEl6Dri2E9FfmJoGxYQY7vYJkURNX04Vj64tdi535tPrpkuf9Sm0lNr3QTKdHQh0DdNRsaa62FLQNQEEw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5"
}
},
"node_modules/@jiaminghi/c-render": {
"version": "0.4.3",
"resolved": "https://registry.npmmirror.com/@jiaminghi/c-render/-/c-render-0.4.3.tgz",
"integrity": "sha512-FJfzj5hGj7MLqqqI2D7vEzHKbQ1Ynnn7PJKgzsjXaZpJzTqs2Yw5OSeZnm6l7Qj7jyPAP53lFvEQNH4o4j6s+Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/bezier-curve": "*",
"@jiaminghi/color": "*",
"@jiaminghi/transition": "*"
}
},
"node_modules/@jiaminghi/charts": {
"version": "0.2.18",
"resolved": "https://registry.npmmirror.com/@jiaminghi/charts/-/charts-0.2.18.tgz",
"integrity": "sha512-K+HXaOOeWG9OOY1VG6M4mBreeeIAPhb9X+khG651AbnwEwL6G2UtcAQ8GWCq6GzhczcLwwhIhuaHqRygwHC0sA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/c-render": "^0.4.3"
}
},
"node_modules/@jiaminghi/color": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/@jiaminghi/color/-/color-1.1.3.tgz",
"integrity": "sha512-ZY3hdorgODk4OSTbxyXBPxAxHPIVf9rPlKJyK1C1db46a50J0reFKpAvfZG8zMG3lvM60IR7Qawgcu4ZDO3+Hg==",
"license": "MIT"
},
"node_modules/@jiaminghi/data-view": {
"version": "2.10.0",
"resolved": "https://registry.npmmirror.com/@jiaminghi/data-view/-/data-view-2.10.0.tgz",
"integrity": "sha512-Cud2MTiMcqc5k2KWabR/svuVQmXHANqURo+yj40370/LdI/gyUJ6LG203hWXEnT1nMCeiv/SLVmxv3PXLScCeA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/charts": "*"
}
},
"node_modules/@jiaminghi/transition": {
"version": "1.1.11",
"resolved": "https://registry.npmmirror.com/@jiaminghi/transition/-/transition-1.1.11.tgz",
"integrity": "sha512-owBggipoHMikDHHDW5Gc7RZYlVuvxHADiU4bxfjBVkHDAmmck+fCkm46n2JzC3j33hWvP9nSCAeh37t6stgWeg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.5.5"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
@ -5557,6 +5614,56 @@
"resolved": "https://registry.npmmirror.com/@intlify/shared/-/shared-9.14.4.tgz",
"integrity": "sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA=="
},
"@jiaminghi/bezier-curve": {
"version": "0.0.9",
"resolved": "https://registry.npmmirror.com/@jiaminghi/bezier-curve/-/bezier-curve-0.0.9.tgz",
"integrity": "sha512-u9xJPOEl6Dri2E9FfmJoGxYQY7vYJkURNX04Vj64tdi535tPrpkuf9Sm0lNr3QTKdHQh0DdNRsaa62FLQNQEEw==",
"requires": {
"@babel/runtime": "^7.5.5"
}
},
"@jiaminghi/c-render": {
"version": "0.4.3",
"resolved": "https://registry.npmmirror.com/@jiaminghi/c-render/-/c-render-0.4.3.tgz",
"integrity": "sha512-FJfzj5hGj7MLqqqI2D7vEzHKbQ1Ynnn7PJKgzsjXaZpJzTqs2Yw5OSeZnm6l7Qj7jyPAP53lFvEQNH4o4j6s+Q==",
"requires": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/bezier-curve": "*",
"@jiaminghi/color": "*",
"@jiaminghi/transition": "*"
}
},
"@jiaminghi/charts": {
"version": "0.2.18",
"resolved": "https://registry.npmmirror.com/@jiaminghi/charts/-/charts-0.2.18.tgz",
"integrity": "sha512-K+HXaOOeWG9OOY1VG6M4mBreeeIAPhb9X+khG651AbnwEwL6G2UtcAQ8GWCq6GzhczcLwwhIhuaHqRygwHC0sA==",
"requires": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/c-render": "^0.4.3"
}
},
"@jiaminghi/color": {
"version": "1.1.3",
"resolved": "https://registry.npmmirror.com/@jiaminghi/color/-/color-1.1.3.tgz",
"integrity": "sha512-ZY3hdorgODk4OSTbxyXBPxAxHPIVf9rPlKJyK1C1db46a50J0reFKpAvfZG8zMG3lvM60IR7Qawgcu4ZDO3+Hg=="
},
"@jiaminghi/data-view": {
"version": "2.10.0",
"resolved": "https://registry.npmmirror.com/@jiaminghi/data-view/-/data-view-2.10.0.tgz",
"integrity": "sha512-Cud2MTiMcqc5k2KWabR/svuVQmXHANqURo+yj40370/LdI/gyUJ6LG203hWXEnT1nMCeiv/SLVmxv3PXLScCeA==",
"requires": {
"@babel/runtime": "^7.5.5",
"@jiaminghi/charts": "*"
}
},
"@jiaminghi/transition": {
"version": "1.1.11",
"resolved": "https://registry.npmmirror.com/@jiaminghi/transition/-/transition-1.1.11.tgz",
"integrity": "sha512-owBggipoHMikDHHDW5Gc7RZYlVuvxHADiU4bxfjBVkHDAmmck+fCkm46n2JzC3j33hWvP9nSCAeh37t6stgWeg==",
"requires": {
"@babel/runtime": "^7.5.5"
}
},
"@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",

View File

@ -21,6 +21,7 @@
"@ant-design/colors": "^7.0.0",
"@ant-design/icons-vue": "^6.1.0",
"@icon-park/vue-next": "^1.4.2",
"@jiaminghi/data-view": "^2.10.0",
"@tinymce/tinymce-vue": "^5.1.0",
"ant-design-vue": "^4.0.1",
"axios": "^1.4.0",

View File

@ -0,0 +1,19 @@
/**
* 区域模块接口
*/
import request from '@/utils/request'
// 获取项目列表
export const getProjectList = (params) => request.basic.get('/api/v1/service-project-categories', params)
// 获取单挑数据
export const getItem = (id) => request.basic.get(`/api/v1/service-project-categories/${id}`)
// 添加条目
export const createItem = (params) => request.basic.post('/api/v1/service-project-categories', params)
// 更新role
export const updateItem = (params) => request.basic.put(`/api/v1/service-project-categories/${params.id}`, params)
// 删除数据
export const delItem = (id) => request.basic.delete(`/api/v1/service-project-categories/${id}`)
export const getProjectListAll = (params) => request.basic.get('/api/v1/service-project-categories/all',params)

View File

@ -16,3 +16,5 @@ export const delItem = (id) => request.basic.delete(`/api/v1/customers/${id}`)
//获取用户数量
export const getCount=(params)=>request.basic.get('/api/v1/customers/count',params)
//创建工单
export const createOrderItem=(params)=> request.basic.post('/api/v1/orders', params)

View File

@ -0,0 +1,19 @@
/**
* 区域模块接口
*/
import request from '@/utils/request'
// 获取项目列表
export const getProjectList = (params) => request.basic.get('/api/v1/service-projects', params)
// 获取单挑数据
export const getItem = (id) => request.basic.get(`/api/v1/service-projects/${id}`)
// 添加条目
export const createItem = (params) => request.basic.post('/api/v1/service-projects', params)
// 更新role
export const updateItem = (params) => request.basic.put(`/api/v1/service-projects/${params.id}`, params)
// 删除数据
export const delItem = (id) => request.basic.delete(`/api/v1/service-projects/${id}`)
export const getProjectListAll = (params) => request.basic.get('/api/v1/service-projects/all', params)

BIN
src/assets/imgs/bg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

@ -1,114 +1,146 @@
<!-- AreaCascader.vue -->
<template>
<a-cascader v-model:value="modelValue" :options="options" :load-data="loadData" :placeholder="placeholder"
:style="style" :disabled="disabled" :show-search="showSearch" :allow-clear="allowClear"
:change-on-select="changeOnSelect" :field-names="fieldNames" @change="handleChange" />
<a-cascader
v-model:value="modelValue"
:options="options"
:load-data="loadData"
:placeholder="placeholder"
:style="style"
:disabled="disabled"
:show-search="showSearch"
:allow-clear="allowClear"
:change-on-select="changeOnSelect"
:field-names="fieldNames"
@change="handleChange"
ref="cascaderRef"
/>
</template>
<script setup>
import { ref, watch, onMounted,defineModel } from 'vue';
import apis from '@/apis'
import { useDicsStore } from '@/store'
const dicsStore = useDicsStore()
// 使 defineModel v-model
import { ref, watch, nextTick, defineModel, onMounted } from 'vue';
import apis from '@/apis';
import { useDicsStore } from '@/store';
const dicsStore = useDicsStore();
const modelValue = defineModel();
// props
const props = defineProps({
placeholder: {
type: String,
default: '请选择省市区'
},
style: {
type: Object,
default: () => ({ width: '100%' })
},
disabled: {
type: Boolean,
default: false
},
showSearch: {
type: Boolean,
default: true
},
allowClear: {
type: Boolean,
default: true
},
changeOnSelect: {
type: Boolean,
default: false //
},
fieldNames: {
type: Object,
default: () => ({
label: 'label',
value: 'code',
// children: 'children'
})
}
placeholder: { type: String, default: '请选择省市区' },
style: { type: Object, default: () => ({ width: '100%' }) },
disabled: { type: Boolean, default: false },
showSearch: { type: Boolean, default: true },
allowClear: { type: Boolean, default: true },
changeOnSelect: { type: Boolean, default: false },
fieldNames: {
type: Object,
default: () => ({
label: 'label',
value: 'code',
// children: 'children' // children
})
}
});
// emit
const emit = defineEmits(['change']);
//
const options = ref([]);
// 🔁 store
watch(
() => dicsStore.provinceOptions,
(newVal) => {
if (newVal && newVal.length > 0) {
options.value = newVal
options.value = newVal;
}
},
{ immediate: true } // 🔥
)
// onMounted(async () => {
// // 使 store
// options.value = await dicsStore.provinceOptions
// });
{ immediate: true }
);
// 🔁 modelValue
watch(
() => modelValue?.value,
async (val) => {
if (!val || !Array.isArray(val) || val.length <= 1) return;
//
const loadData = async (selectedOptions) => {
console.log('加载子节点, 选中选项:', selectedOptions);
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
//
await nextTick();
try {
const response = await apis.common.getAreaList({ current:1,pageSize:100,parentId: targetOption.id });
//
for (let i = 1; i < val.length; i++) {
const parentCode = val[i - 1];
const currentCode = val[i];
targetOption.loading = false;
//
let targetNode;
if (i === 1) {
// options
targetNode = options.value.find(opt => opt.code === parentCode);
} else {
//
targetNode = findNodeInOptions(options.value, parentCode);
}
if (Array.isArray(response.data)) {
const children = response.data.map(item => ({
...item,
isLeaf: !item.hasChild // /
}));
if (targetNode && !targetNode.children) {
// loadData
await loadData([targetNode]);
}
// children
targetOption.children = children;
} else {
targetOption.children = [];
}
//
options.value = [...options.value];
} catch (error) {
console.error('加载子节点失败:', error);
targetOption.children = [];
targetOption.loading = false;
//
await nextTick();
}
},
{ immediate: true } // 🔥
);
// 🔍
function findNodeInOptions(options, code) {
for (const opt of options) {
if (opt.code === code) return opt;
if (opt.children) {
const found = findNodeInOptions(opt.children, code);
if (found) return found;
}
}
return null;
}
// 🌐
const loadData = async (selectedOptions) => {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
try {
const parentId = targetOption.id || targetOption.code; // id code
const response = await apis.common.getAreaList({
current: 1,
pageSize: 100,
parentId
});
targetOption.loading = false;
if (Array.isArray(response.data)) {
const children = response.data.map(item => ({
...item,
isLeaf: !item.hasChild,
label: item.label || item.name, //
value: item.code
}));
targetOption.children = children;
} else {
targetOption.children = [];
}
//
options.value = [...options.value];
} catch (error) {
console.error('加载子节点失败:', error);
targetOption.children = [];
targetOption.loading = false;
}
};
//
// 📣
const handleChange = (value, selectedOptions) => {
emit('change', value, selectedOptions.map(option => option.label));
emit('change', value, selectedOptions?.map(opt => opt.label) || []);
};
</script>
<style scoped>
/* 可根据需要添加样式 */
</style>
</script>

View File

@ -235,12 +235,14 @@ const clearMarkers = () => {
searchResult.value = null;
};
const handleChange=(e)=>{
console.log(searchList.value)
const item = searchList.value.find(item=>item.id===e)
const obj={
lng:item.location.lng,
lat:item.location.lat,
addres:item.address
addres:item.name
}
console.log(obj)
emit('handleGetLng', obj)
}
</script>

View File

View File

@ -1,23 +1,21 @@
<template>
<a-layout-header
class="basic-header"
:class="cpClassNames"
:style="cpStyles">
<a-layout-header class="basic-header" :class="cpClassNames" :style="cpStyles">
<!-- 左侧 -->
<div
v-if="cpShowLeftSlot"
class="basic-header__left">
<div v-if="cpShowLeftSlot" class="basic-header__left">
<slot name="left"></slot>
</div>
<!-- 中间 -->
<div
v-if="cpShowDefaultSlot"
class="basic-header__center">
<div v-if="cpShowDefaultSlot" class="basic-header__center">
<slot></slot>
</div>
<!-- 右侧 -->
<div class="basic-header__right">
<a-space :size="16">
<a-tooltip title="居家服务数据大屏">
<action-button @click="handleBigScreen">
<BarChartOutlined />
</action-button>
</a-tooltip>
<action-button @click="handleConfig">
<setting-outlined></setting-outlined>
</action-button>
@ -28,10 +26,7 @@
<a-spin />
<template #overlay>
<a-menu v-model:selectedKeys="current">
<a-menu-item
v-for="(item, key) in langData"
:key="key"
@click="handleLang(key)">
<a-menu-item v-for="(item, key) in langData" :key="key" @click="handleLang(key)">
{{ item.icon }} {{ item.label }}
</a-menu-item>
</a-menu>
@ -40,9 +35,7 @@
<a-dropdown :trigger="['click']">
<action-button :style="{ height: '44px' }">
<a-avatar
class="mr-8-1 display-inline-flex justify-content-center"
:size="24"
<a-avatar class="mr-8-1 display-inline-flex justify-content-center" :size="24"
:src="userInfo?.avatar">
</a-avatar>
<span>{{ userInfo?.name }}</span>
@ -50,15 +43,11 @@
<a-spin />
<template #overlay>
<a-menu>
<a-menu-item
key="edit"
@click="handleOpen">
<a-menu-item key="edit" @click="handleOpen">
<edit-outlined />
{{ $t('component.RightContent.profile') }}
</a-menu-item>
<a-menu-item
key="logout"
@click="handleLogout">
<a-menu-item key="logout" @click="handleLogout">
<login-outlined></login-outlined>
{{ $t('component.RightContent.logout') }}
</a-menu-item>
@ -75,7 +64,7 @@ import { Modal } from 'ant-design-vue'
import { storeToRefs } from 'pinia'
import { computed, useSlots, ref } from 'vue'
import { useRouter } from 'vue-router'
import { LoginOutlined, SettingOutlined, EditOutlined, TranslationOutlined } from '@ant-design/icons-vue'
import { LoginOutlined, SettingOutlined, EditOutlined, TranslationOutlined, BarChartOutlined } from '@ant-design/icons-vue'
import { useAppStore, useUserStore } from '@/store'
import ActionButton from './ActionButton.vue'
import { theme as antTheme } from 'ant-design-vue'

View File

@ -3,8 +3,10 @@ import {spliceUrl} from '@/utils/util'
import App from '@/App.vue'
import { useCore } from '@/core'
import './assets/iconfont/iconfont.css';
// import dataV from '@jiaminghi/data-view'
const app = createApp(App)
// app.use(dataV)
app.config.globalProperties.$spliceUrl=spliceUrl
useCore(app)
app.mount('#app')

View File

@ -55,4 +55,12 @@ export const constantRoutes = [
title: '平台选择',
},
},
{
path: '/bigScreen',
name: 'bigScreen',
component: () => import('@/views/login/bigScreen.vue'),
meta: {
title: '居家服务数据大屏',
},
},
]

View File

@ -15,6 +15,7 @@ import severObj from './severObj'
import workorder from './workorder'
import service from './service'
import serviceStaff from './serviceStaff'
import serverSet from './serverSet'
export default [
...home,
// ...form,
@ -32,5 +33,6 @@ export default [
// ...other,
...workorder,
...service,
...serviceStaff
...serviceStaff,
...serverSet
]

View File

@ -20,7 +20,6 @@ const options = {
},
interceptorRequestCatch: () => {},
interceptorResponse: (response) => {
console.log('返回',response.data)
// 错误处理
const { success, msg = 'Network Error' } = response.data || {}
if (![true].includes(success)) {

View File

@ -1,180 +0,0 @@
<template>
<a-modal :open="modal.open" :title="modal.title" :width="600" :confirm-loading="modal.confirmLoading"
:after-close="onAfterClose" :cancel-text="cancelText" @ok="handleOk" @cancel="handleCancel">
<a-card>
<a-form ref="formRef" :model="formData" :rules="formRules">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="姓名" name="name">
<a-input v-model:value="formData.name" placeholder="请输入姓名" />
</a-form-item>
</a-col>
<!-- 性别 -->
<a-col :span="12">
<a-form-item label="性别" name="gender">
<a-radio-group v-model:value="formData.gender">
<a-radio value="1"></a-radio>
<a-radio value="2"></a-radio>
</a-radio-group>
</a-form-item>
</a-col>
<!-- 证件号码 -->
<a-col :span="12">
<a-form-item label="身份证号" name="idCard">
<a-input v-model:value="formData.idCard" placeholder="请输入证件号码" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="电话" name="phone">
<a-input v-model:value="formData.phone" placeholder="请输入电话" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="电话" name="phone">
<a-input v-model:value="formData.phone" placeholder="请输入电话" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="护理人员类型" name="serviceType">
<a-select v-model:value="formData.serviceType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="护理人员状态" name="status">
<a-select v-model:value="formData.status" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_STATUS" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="用工形式" name="workType">
<a-select v-model:value="formData.workType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.USE_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="所属服务组织" name="stationLables">
<node-tree v-model:value="formData.stationLables" />
</a-form-item>
</a-col>
<!-- <a-col :span="8">
<a-form-item label="组织所在区域" name="areaLabels">
<node-tree v-model:value="formData.areaLabels" />
</a-form-item>
</a-col> -->
</a-row>
</a-form>
</a-card>
</a-modal>
</template>
<script setup>
import { cloneDeep } from 'lodash-es'
import { ref, defineProps } from 'vue'
import { config } from '@/config'
import apis from '@/apis'
import { useForm, useModal } from '@/hooks'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import NodeTree from '@/components/NodeTree/index.vue'
const emit = defineEmits(['ok'])
const activeKey = ref('1')
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const cancelText = ref('取消')
const dicsStore = useDicsStore()
/**
* 新建
*/
function handleCreate() {
showModal({
type: 'create',
title: '新增服务人员',
})
}
/**
* 编辑
*/
function handleEdit(record = {}) {
showModal({
type: 'edit',
title: '编辑项',
})
formRecord.value = record
formData.value = cloneDeep(record)
}
/**
* 确定
*/
function handleOk() {
formRef.value
.validateFields()
.then(async (values) => {
try {
showLoading()
const params = {
...formData.value,
}
let result = null
switch (modal.value.type) {
case 'create':
result = await apis.serverObj.createItem(params).catch(() => {
throw new Error()
})
break
case 'edit':
result = await apis.serverObj.updateItem(params).catch(() => {
throw new Error()
})
break
}
hideLoading()
if (config('http.code.success') === result?.code) {
hideModal()
emit('ok')
}
} catch (error) {
hideLoading()
}
})
.catch(() => {
hideLoading()
})
}
/**
* 取消
*/
function handleCancel() {
hideModal()
}
/**
* 关闭后
*/
function onAfterClose() {
resetForm()
hideLoading()
}
defineExpose({
handleEdit,
handleCreate,
})
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,143 @@
<template>
<a-modal :open="modal.open" :title="modal.title" :width="600" :confirm-loading="modal.confirmLoading"
:after-close="onAfterClose" :cancel-text="cancelText" @ok="handleOk" @cancel="handleCancel">
<a-card>
<a-form ref="formRef" :model="formData" :rules="formRules">
<a-row :gutter="24">
<a-col :span="24">
<a-form-item label="类型" name="categoryType">
<a-select v-model:value="formData.categoryType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.PROJECT_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="项目类型名称" name="name">
<a-input v-model:value="formData.name" placeholder="请输入项目类型名称"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="分类描述" name="remark">
<a-input v-model:value="formData.remark"></a-input>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item :label="'状态'" name="status">
<a-radio-group v-model:value="formData.status" :options="[
{ label: '启用', value: 'enabled' },
{ label: '停用', value: 'disabled' },
]"></a-radio-group>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
</a-modal>
</template>
<script setup>
import { cloneDeep } from 'lodash-es'
import { ref, defineProps } from 'vue'
import { config } from '@/config'
import apis from '@/apis'
import { useForm, useModal } from '@/hooks'
import { useDicsStore } from '@/store'
import { message } from 'ant-design-vue'
const emit = defineEmits(['ok'])
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const cancelText = ref('取消')
const dicsStore = useDicsStore()
formRules.value = {
categoryType: [{ required: true, message: '请选择类型', trigger: ['blur', 'change'] }],
name: [{ required: true, message: '请输入项目分类名称', trigger: 'blur' }],
}
/**
* 新建
*/
function handleCreate() {
showModal({
type: 'create',
title: '新增项目分类',
})
formData.value.status='enabled'
}
/**
* 编辑
*/
function handleEdit(record = {}) {
showModal({
type: 'edit',
title: '编辑项目分类',
})
formData.value = cloneDeep(record)
}
/**
* 确定
*/
function handleOk() {
formRef.value
.validateFields()
.then(async (values) => {
try {
showLoading()
const params = {
...formData.value,
}
let result = null
switch (modal.value.type) {
case 'create':
result = await apis.projectType.createItem(params).catch(() => {
throw new Error()
})
console.log(result)
break
case 'edit':
result = await apis.projectType.updateItem(params).catch(() => {
throw new Error()
})
break
}
hideLoading()
if (config('http.code.success') === result?.success) {
hideModal()
emit('ok')
}
} catch (error) {
hideLoading()
}
})
.catch(() => {
hideLoading()
})
}
/**
* 取消
*/
function handleCancel() {
hideModal()
}
/**
* 关闭后
*/
function onAfterClose() {
resetForm()
hideLoading()
}
defineExpose({
handleEdit,
handleCreate,
})
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,241 @@
<template>
<a-modal :open="modal.open" :title="modal.title" :width="600" :confirm-loading="modal.confirmLoading"
:after-close="onAfterClose" :cancel-text="cancelText" @ok="handleOk" @cancel="handleCancel">
<a-card>
<a-form ref="formRef" :model="formData" :rules="formRules">
<a-row :gutter="24">
<a-col :span="24">
<a-form-item label="类型" name="categoryType">
<a-select v-model:value="formData.categoryType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.PROJECT_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
<span style="color: #ff4d4f;font-size: 12px;">温馨提示类型保存后不可修改请认真选择</span>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="服务项目分类" name="categoryId">
<a-select v-model:value="formData.categoryId" allowClear>
<a-select-option v-for="item in categoryList" :key="item.id" :value="item.id">{{
item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="服务项目名称" name="name">
<a-input v-model:value="formData.name"></a-input>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="单价" name="price">
<a-input-number v-model:value="formData.price" style="width: 100%;">
<template #addonAfter>
<a-select v-model:value="formData.priceUnit" style="width: 100px">
<a-select-option value="次">/</a-select-option>
<a-select-option value="时">/</a-select-option>
</a-select>
</template>
</a-input-number>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="单次服务时长" name="duration">
<a-input-number v-model:value="formData.duration" style="width: 100%;">
<template #addonAfter>
<span>分钟</span>
</template>
</a-input-number>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="服务频次" name="frequency">
<a-input-number v-model:value="formData.frequency" style="width: 100%;">
<template #addonAfter>
<a-select v-model:value="formData.frequencyUnit" style="width: 80px">
<a-select-option value="元/次">/</a-select-option>
<a-select-option value="元/台">/</a-select-option>
</a-select>
</template>
</a-input-number>
</a-form-item>
</a-col>
<a-col span="12">
<a-form-item label="服务形式" name="serviceFormat">
<a-select v-model:value="formData.serviceFormat" style="width: 100%;">
<a-select-option v-for="item in dicsStore.dictOptions.Service_Format" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="计时标准" name="timeKeeping">
<a-input v-model:value="formData.timeKeeping" style="width: 100%;">
<template #addonAfter>
<a-select v-model:value="formData.timeKeepingUnit" style="width: 120px">
<a-select-option value="小时/次">小时/</a-select-option>
<a-select-option value="小时/平方">小时/平方</a-select-option>
<a-select-option value="小时/台">小时/</a-select-option>
<a-select-option value="小时/组">小时/</a-select-option>
<a-select-option value="小时/件">小时/</a-select-option>
<a-select-option value="小时/个">小时/</a-select-option>
<a-select-option value="小时/张">小时/</a-select-option>
<a-select-option value="小时/辆">小时/</a-select-option>
<a-select-option value="小时/项">小时/</a-select-option>
</a-select>
</template>
</a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="服务内容" name="content">
<a-textarea v-model:value="formData.content" placeholder="请输入内容/简介最多500字" :rows="4" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="封面图片" name="imgList">
<gx-upload v-model="formData.imgList" accept-types=".jpg,.png,.webp" :fileNumber="1" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="详情图片" name="detailImgList">
<gx-upload v-model="formData.detailImgList" accept-types=".jpg,.png,.webp"
:fileNumber="20" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="服务项目视频" name="detailImgList">
<a-upload v-model:file-list="fileList"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76" accept=".mp4,.3gp,.m3u8">
<a-button>
<upload-outlined></upload-outlined>
上传
</a-button>
</a-upload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
</a-modal>
</template>
<script setup>
import GxUpload from '@/components/GxUpload/index.vue'
import { cloneDeep } from 'lodash-es'
import { ref, defineProps } from 'vue'
import { config } from '@/config'
import apis from '@/apis'
import { useForm, useModal } from '@/hooks'
import { useDicsStore } from '@/store'
import { message } from 'ant-design-vue'
import { UploadOutlined } from '@ant-design/icons-vue';
const emit = defineEmits(['ok'])
const fileList=ref([])
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const cancelText = ref('取消')
const dicsStore = useDicsStore()
formRules.value = {
categoryType: [{ required: true, message: '请选择类型', trigger: ['blur', 'change'] }],
categoryId: [{ required: true, message: '请选择类型', trigger: ['blur', 'change'] }],
name: [{ required: true, message: '请输入项目分类名称', trigger: 'blur' }],
duration:[{ required: true, message: '请输入项目分类名称', trigger: 'blur' }],
}
const props = defineProps({
categoryList: {
type: Array,
default: []
}
})
/**
* 新建
*/
function handleCreate() {
showModal({
type: 'create',
title: '新增',
})
formData.value = {
priceUnit: '元/次',
frequencyUnit: '元/次',
timeKeepingUnit: '小时/次'
}
}
/**
* 编辑
*/
function handleEdit(record = {}) {
showModal({
type: 'edit',
title: '编辑',
})
formRecord.value = record
formData.value = cloneDeep(record)
}
/**
* 确定
*/
function handleOk() {
formRef.value
.validateFields()
.then(async (values) => {
try {
showLoading()
const params = {
...formData.value,
}
let result = null
switch (modal.value.type) {
case 'create':
result = await apis.serviceProject.createItem(params).catch(() => {
throw new Error()
})
console.log(result)
break
case 'edit':
result = await apis.serviceProject.updateItem(params).catch(() => {
throw new Error()
})
break
}
hideLoading()
if (config('http.code.success') === result?.success) {
hideModal()
emit('ok')
}
} catch (error) {
hideLoading()
}
})
.catch(() => {
hideLoading()
})
}
/**
* 取消
*/
function handleCancel() {
hideModal()
}
/**
* 关闭后
*/
function onAfterClose() {
resetForm()
hideLoading()
}
defineExpose({
handleEdit,
handleCreate,
})
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,200 @@
<template>
<a-form :model="searchFormData" labelAlign="left">
<a-row :gutter="24">
<a-col :span="6">
<a-form-item label="类型" name="categoryType">
<a-select v-model:value="searchFormData.categoryType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.PROJECT_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<!-- 所在区域 -->
<a-col :span="6">
<a-form-item label="项目分类" name="categoryId">
<a-select v-model:value="searchFormData.categoryId" allowClear>
<a-select-option v-for="item in categoryList" :key="item.id" :value="item.name">{{
item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="6">
<a-form-item label="项目名称" name="name">
<a-input v-model:value="searchFormData.name"></a-input>
</a-form-item>
</a-col>
<!-- 操作按钮 -->
<a-col class="align-left" :span="6">
<a-space>
<a-button @click="handleResetSearch">{{ $t('button.reset') }}</a-button>
<a-button ghost type="primary" @click="handleSearch">
{{ $t('button.search') }}
</a-button>
</a-space>
</a-col>
</a-row>
</a-form>
<a-card title="服务项目列表">
<template #extra>
<a-space>
<a-button type="primary" @click="$refs.editDialogRef.handleCreate(record)">新建</a-button>
</a-space>
</template>
<a-table :columns="columns" :data-source="listData" bordered="true" :loading="loading"
:pagination="paginationState" :scroll="{ x: 'max-content' }" @change="onTableChange">
<template #bodyCell="{ index, column, record }">
<template v-if="column.key === 'serialNumber'">
<span>{{ index + 1 }}</span>
</template>
<template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template>
<template v-if="'action' === column.key">
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
</x-action-button>
<x-action-button @click="handleDelete(record)">
<span style="color: #ff4d4f;">删除</span>
</x-action-button>
</template>
</template>
</a-table>
</a-card>
<edit-dialog ref="editDialogRef" @ok="onOk" :categoryList="categoryList"></edit-dialog>
</template>
<script setup>
import { message, Modal } from 'ant-design-vue'
import { ref } from 'vue'
import apis from '@/apis'
import { config } from '@/config'
import { usePagination } from '@/hooks'
import { useI18n } from 'vue-i18n'
import EditDialog from './projectEditDialog.vue'
import { useDicsStore } from '@/store'
defineOptions({
name: 'serverProject',
})
const dicsStore = useDicsStore()
const categoryList=ref([])
const columns = [
{ title: '序号', dataIndex: 'serialNumber', key: 'serialNumber', align: 'center', width: 80, },
{ title: '类型', dataIndex: 'categoryType', key: 'categoryType', align: 'center', width: 100, },
{ title: '分类名称', dataIndex: 'name', key: 'name', align: 'center', width: 180, },
{ title: '项目名称', dataIndex: 'name', key: 'name', align: 'center', },
{ title: '价格', dataIndex: 'price', key: 'price', align: 'center', },
{ title: '简介', dataIndex: 'remark', key: 'remark', align: 'center', },
{ title: '操作', dataIndex: 'action', key: 'action', align: 'center', width: 120, fixed: 'right', }
];
const { t } = useI18n() // t
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
const editDialogRef = ref()
getPageList()
getCategoriesAll()
async function getCategoriesAll() {
try {
console.log(111)
const { success, data, total } = await apis.projectType
.getProjectListAll({
pageSize:100, current:1,
})
.catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
categoryList.value = data.map(item=>({id:item.id,name:item.name}))
}
} catch (error) {
}
}
async function getPageList() {
try {
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceProject
.getProjectList({
pageSize, current,
...searchFormData.value,
})
.catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
listData.value = data
paginationState.total = total
}
} catch (error) {
}
}
/**
* 删除
*/
function handleDelete({ id }) {
Modal.confirm({
title: t('pages.system.user.delTip'),
content: t('button.confirm'),
okText: t('button.confirm'),
onOk: () => {
return new Promise((resolve, reject) => {
; (async () => {
try {
const { success } = await apis.serviceProject.delItem(id).catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
resolve()
message.success(t('component.message.success.delete'))
await getPageList()
}
} catch (error) {
reject()
}
})()
})
},
})
}
/**
* 分页
*/
function onTableChange({ current, pageSize }) {
paginationState.current = current
paginationState.pageSize = pageSize
getPageList()
}
/**
* 搜索
*/
function handleSearch() {
resetPagination()
getPageList()
}
/**
* 重置
*/
function handleResetSearch() {
searchFormData.value = {}
resetPagination()
getPageList()
}
/**
* 编辑完成
*/
async function onOk() {
await getPageList()
}
</script>
<style lang="less" scoped></style>

View File

@ -1,98 +1,51 @@
<template>
<x-search-bar class="mb-8-2">
<template #default="{ gutter, colSpan }">
<a-form :model="searchFormData" layout="inline" labelAlign="left">
<a-row :gutter="[24, 24]">
<!-- 所在区域 -->
<a-col :span="8">
<a-form-item label="所属服务组织" name="station">
<node-tree v-model:value="searchFormData.station" />
</a-form-item>
</a-col>
<!-- 姓名 -->
<a-col :span="8">
<a-form-item label="姓名" name="name">
<a-input v-model:value="searchFormData.name" placeholder="请输入姓名" />
</a-form-item>
</a-col>
<!-- 身份证号 -->
<a-col :span="8">
<a-form-item label="联系电话" name="phone">
<a-input v-model:value="searchFormData.phone" placeholder="请输入联系电话" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="护理人员类型" name="serviceType">
<a-select v-model:value="searchFormData.serviceType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="护理人员状态" name="status">
<a-select v-model:value="searchFormData.status" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_STATUS" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="用工形式" name="workType">
<a-select v-model:value="searchFormData.workType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.USE_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<!-- 操作按钮 -->
<a-col class="align-right" :span="24">
<a-space>
<a-button @click="handleResetSearch">{{ $t('button.reset') }}</a-button>
<a-button ghost type="primary" @click="handleSearch">
{{ $t('button.search') }}
</a-button>
</a-space>
<a-card>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="项目分类">
<a-row :gutter="8" :wrap="false">
<a-col flex="auto">
<a-card title="服务项目分类列表">
<template #extra>
<a-space>
<a-button type="primary"
@click="$refs.editDialogRef.handleCreate(record)">新建</a-button>
</a-space>
</template>
<a-table :columns="columns" :data-source="listData" bordered="true" :loading="loading"
:pagination="paginationState" :scroll="{ x: 'max-content' }" @change="onTableChange">
<template #bodyCell="{ index, column, record }">
<template v-if="column.key === 'serialNumber'">
<span>{{ index + 1 }}</span>
</template>
<template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 'enabled'" color="green">启用</a-tag>
<a-tag v-else>停用</a-tag>
</template>
<template v-if="'action' === column.key">
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
</x-action-button>
<x-action-button @click="handleDelete(record)">
<span style="color: #ff4d4f;">删除</span>
</x-action-button>
</template>
</template>
</a-table>
</a-card>
</a-col>
</a-row>
</a-form>
</template>
</x-search-bar>
<a-row :gutter="8" :wrap="false">
<a-col flex="auto">
<a-card title="服务人员列表">
<template #extra>
<a-space>
<a-button type="primary" @click="$refs.editDialogRef.handleCreate(record)">新建</a-button>
<a-button type="primary">导出</a-button>
<a-button type="dashed">导出记录</a-button>
</a-space>
</template>
<a-table :columns="columns" :data-source="listData" bordered="true" :loading="loading"
:pagination="paginationState" :scroll="{ x: 'max-content' }" @change="onTableChange">
<template #bodyCell="{ index, column, record }">
<template v-if="column.key === 'serialNumber'">
<span>{{ index + 1 }}</span>
</template>
<template v-if="'action' === column.key">
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
</x-action-button>
<x-action-button @click="handleDelete(record)">
<span style="color: #ff4d4f;">删除</span>
</x-action-button>
</template>
</template>
</a-table>
</a-card>
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane key="2" tab="服务项目">
<ServerProject />
</a-tab-pane>
</a-tabs>
</a-card>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
<detail ref="detailRef"></detail>
</template>
<script setup>
@ -105,14 +58,14 @@ import { useI18n } from 'vue-i18n'
import EditDialog from './components/EditDialog.vue'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import detail from './components/detail.vue'
import dayjs from 'dayjs'
import NodeTree from '@/components/NodeTree/index.vue'
import ServerProject from './components/serverProject.vue'
defineOptions({
name: 'serverProjectManage',
})
const dicsStore = useDicsStore()
const activeKey = ref('1')
const columns = [
{
title: '序号',
@ -122,157 +75,53 @@ const columns = [
width: 80,
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
title: '类型',
dataIndex: 'categoryType',
key: 'categoryType',
align: 'center',
width: 100,
},
{
title: '性别',
dataIndex: 'gender',
key: 'gender',
align: 'center',
width: 80,
},
{
title: '电话',
dataIndex: 'phone',
key: 'phone',
align: 'center',
width: 80,
},
{
title: '身份证号',
dataIndex: 'idCard',
key: 'idCard',
title: '分类名称',
dataIndex: 'name',
key: 'name',
align: 'center',
width: 180,
},
{
title: '护理人员类型',
dataIndex: 'serviceType',
key: 'serviceType',
title: '分类描述',
dataIndex: 'remark',
key: 'remark',
align: 'center',
width: 120,
},
{
title: '用工形式',
dataIndex: 'workType',
key: 'workType',
align: 'center',
width: 120,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center',
width: 120,
width: 80,
},
// --- ---
{
title: '护理人员类型',
dataIndex: 'serviceType',
key: 'serviceType',
align: 'center',
width: 130,
},
{
title: '所属服务组织',
dataIndex: 'stationName',
key: 'stationName',
align: 'center',
width: 120,
},
// {
// title: '',
// dataIndex: 'areaLabels',
// key: 'areaLabels',
// align: 'center',
// width: 120,
// },
{
title: '操作',
dataIndex: 'action',
key: 'action',
align: 'center',
width: 180,
width: 120,
fixed: 'right',
}
];
const { t } = useI18n() // t
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
const editDialogRef = ref()
const detailRef = ref()
const treeData = ref([
{
title: 'Node1',
value: '0-0',
key: '0-0',
children: [
{
value: '0-0-1',
key: '0-0-1',
slots: {
title: 'title',
},
},
{
title: 'Child Node2',
value: '0-0-2',
key: '0-0-2',
},
],
},
{
title: 'Node2',
value: '0-1',
key: '0-1',
},
]);
const options = ref([
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
children: [
{
value: 'xihu',
label: 'West Lake',
},
],
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
children: [
{
value: 'zhonghuamen',
label: 'Zhong Hua Men',
},
],
},
],
},])
getPageList()
async function getPageList() {
try {
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceStaffList
const { success, data, total } = await apis.projectType
.getProjectList({
pageSize,
current: current,
@ -290,28 +139,7 @@ async function getPageList() {
}
}
/**核销 */
const checkHandler = (record) => {
Modal.confirm({
title: '即将核销是否继续',
content: t('button.confirm'),
okText: t('button.confirm'),
onOk: async () => {
const params = {
...record,
status: 'success'
}
const { success } = await apis.productOrder.updateItem(params.id, params).catch(() => {
// throw new Error()
})
if (config('http.code.success') === success) {
// resolve()
message.success('核销成功')
await getPageList()
}
},
})
}
/**
* 删除
*/
@ -324,7 +152,7 @@ function handleDelete({ id }) {
return new Promise((resolve, reject) => {
; (async () => {
try {
const { success } = await apis.productOrder.delItem(id).catch(() => {
const { success } = await apis.projectType.delItem(id).catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {

View File

@ -0,0 +1,184 @@
<template>
<div class="screen-container">
<div class="container">
<div class="screen-title">
居家养老服务数据展示
</div>
<div class="screen-content">
<div>
<div>
<div class="card-title">服务对象人口统计</div>
<div class="card-content">
<!-- <dv-active-ring-chart :config="config1" style="width:300px;height:300px" /> -->
</div>
</div>
<div></div>
<div></div>
</div>
<div>
<div></div>
<div></div>
</div>
<div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {ref} from 'vue'
const config1=ref(
{
radius: '40%',
activeRadius: '45%',
data: [
{
name: '周口',
value: 55
},
{
name: '南阳',
value: 120
},
{
name: '西峡',
value: 78
},
{
name: '驻马店',
value: 66
},
{
name: '新乡',
value: 80
}
],
digitalFlopStyle: {
fontSize: 20
},
showOriginValue: true
}
)
</script>
<style scoped lang="less">
.screen-container {
width: 100%;
height: 100vh;
background-image: url(./../../assets/imgs/screenbg.png);
background-size: 100% 100%;
.container {
width: 100%;
height: 100%;
background-image: url(./../../assets/imgs/bg2.png);
background-size: 100% 100%;
.screen-title {
font-size: clamp(2rem, 3vw, 3rem);
/* 自适应字体大小 */
width: 100%;
height: 10vh;
/* 高度根据内容自动调整 */
line-height: 8vh;
/* 调整行高以适应不同字体大小 */
text-align: center;
pointer-events: none;
background-size: cover;
/* 假设背景图片应该覆盖整个元素 */
font-family: ZhenyanG-Flash, sans-serif;
/* 添加备用字体 */
color: #fff;
text-shadow: 0 0 35px rgba(22, 165, 255, .75);
}
.screen-content {
height: 90vh;
display: flex;
gap: 5px;
/* 元素之间的间距,推荐现代写法 */
padding: 0 15px 15px 15px;
box-sizing: border-box;
/* 第一个子元素:左侧,占 1 份 */
&>div:first-child {
flex: 1;
height: 100%;
// background: black;
display: flex;
flex-direction: column;
gap: 5px;
&>div {
flex: 1;
width: 100%;
background-color: rgba(69, 117, 147, .2);
}
}
/* 第二个子元素:中间,占 2 份 */
&>div:nth-child(2) {
flex: 2;
height: 100%;
// background: black;
display: flex;
flex-direction: column;
gap: 5px;
&>div:first-child {
flex: 2;
width: 100%;
}
&>div:last-child {
flex: 1;
width: 100%;
background-color: rgba(69, 117, 147, .2);
}
}
/* 第三个子元素:右侧,占 1 份 */
&>div:last-child {
flex: 1;
height: 100%;
// background: black;
display: flex;
flex-direction: column;
gap: 5px;
&>div {
flex: 1;
width: 100%;
background-color: rgba(69, 117, 147, .2);
}
}
.card-title {
color: #fff;
font-size: 1.33333rem;
height: 4.16667rem;
// margin: 0 24px;
line-height: 4.16667rem;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
border-bottom: 1px solid hsla(0, 0%, 60%, .1);
position: relative;
&::before {
content: "";
width: 2.58333rem;
height: 1.91667rem;
margin: auto 3px auto 0;
background: url(data:image/png;base64,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) no-repeat 50%;
background-size: 50%;
}
}
}
}
}
</style>

View File

@ -172,14 +172,14 @@
<!-- 经度 -->
<a-col :span="12">
<a-form-item label="经度" name="lat">
<a-input v-model:value="formData.archive.lat" placeholder="请输入经度" />
<a-input-number v-model:value="formData.archive.lat" placeholder="请输入经度" style="width: 100%;"/>
</a-form-item>
</a-col>
<!-- 纬度 -->
<a-col :span="12">
<a-form-item label="纬度" name="lag">
<a-input v-model:value="formData.archive.lag" placeholder="请输入纬度" />
<a-input-number v-model:value="formData.archive.lag" placeholder="请输入纬度" style="width: 100%;"/>
</a-form-item>
</a-col>
<gx-map @handleGetLng="handleGetLng" />
@ -578,18 +578,17 @@ function handleOk() {
let params = {
...formData.value,
labels: formData.value.labelsCode ? formData.value.labelsCode.map(item => dicsStore.getDictLabel('Service_Recipient_Category2', item)) : [],
birthDate:dayjs(formData.value.birthDate).format('YYYY-MM-DD')
}
params.archive.idCardPhotos = formData.value.archive.idCardPhotos ? formData.value.archive.idCardPhotos.map(item => spliceUrl(item)) : ['']
params.archive.uploadedDocuments = formData.value.archive.uploadedDocuments ? formData.value.archive.uploadedDocuments.map(item => spliceUrl(item)) : ['']
if(formData.value.governmentPurchasedServiceStartDate.length>0){
params.archive.starGovernmentService=dayjs(formData.value.governmentPurchasedServiceStartDate[0]).format('YYYY-MM-DD')
params.archive.endGovernmentService=dayjs(formData.value.governmentPurchasedServiceStartDate[1]).format('YYYY-MM-DD')
params.archive.idCardPhotos = formData.value.archive.idCardPhotos&&formData.value.archive.idCardPhotos.length>0 ? formData.value.archive.idCardPhotos.map(item => spliceUrl(item)) : ['']
params.archive.uploadedDocuments = formData.value.archive.uploadedDocuments&&formData.value.archive.uploadedDocuments.length>0 ? formData.value.archive.uploadedDocuments.map(item => spliceUrl(item)) : ['']
if(formData.value.governmentPurchasedServiceStartDate&&formData.value.governmentPurchasedServiceStartDate.length>0){
params.archive.starGovernmentService=formData.value.governmentPurchasedServiceStartDate[0]
params.archive.endGovernmentService=formData.value.governmentPurchasedServiceStartDate[1]
}
//
if (params.identityType === '1' && !isValidIdCard(params.identityNo)) {
throw new Error('请输入正确的身份证号码');
return message.error('请输入正确的身份证号码')
}
let result = null
switch (modal.value.type) {
@ -607,11 +606,12 @@ function handleOk() {
break
}
hideLoading()
if (config('http.code.success') === result?.code) {
if (config('http.code.success') === true) {
hideModal()
emit('ok')
}
} catch (error) {
console.log(error.message)
hideLoading()
// message.error(error.message)
}

View File

@ -0,0 +1,318 @@
<template>
<a-form ref="formRef" :model="formData" :rules="formRules">
<a-row :gutter="24">
<!-- 姓名 -->
<a-col :span="12">
<a-form-item label="服务对象" name="name">
<a-input v-model:value="formData.name" placeholder="请输入姓名" disabled />
</a-form-item>
</a-col>
<!-- 性别 -->
<a-col :span="12">
<a-form-item label="服务站点" name="stationId">
<a-select v-model:value="formData.stationId" style="width: 100px; margin-right: 8px;">
<a-select-option v-for="item in stationList" :key="item.id" :value="item.id">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<!-- 出生日期 -->
<a-col :span="12">]
<a-button @click="ceshi">测试</a-button>
<a-form-item label="服务项目" name="serviceItems">
<!-- 显示已选项目 -->
<a-tag v-for="item in selectedServices" :key="item.id" closable @close="handleRemove(item)">
{{ item.name }}
</a-tag>
<a-button @click="showModal2">
<PlusOutlined /> 添加服务
</a-button>
</a-form-item>
</a-col>
</a-row>
</a-form>
<a-button type="primary" @click="visible3=true">Open Modal</a-button>
<a-modal v-model:visible="visible3" title="Basic Modal" :getContainer="() => document.body">
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</a-modal>
<a-modal v-model:open="modalVisible" title="选择服务项目" @ok="handleConfirm" @cancel="handleCancel2" okText="确认"
cancelText="取消" :width="600">
<a-table :dataSource="serviceList" :columns="columns" :row-selection="rowSelection" :pagination="false"
:loading="loading" size="small">
<template #bodyCell="{ index, column, record }">
<template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template>
</template>
</a-table>
</a-modal>
</template>
<script setup>
import { cloneDeep } from 'lodash-es'
import { ref, defineProps,defineExpose } from 'vue'
import { config } from '@/config'
import apis from '@/apis'
import { useForm, useModal } from '@/hooks'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import { validatePhone, validateEmail, validateIdCard } from '@/utils/validate'
import { getBirthDate, spliceUrl } from '@/utils/util'
import dayjs from 'dayjs'
import { PlusOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
const emit = defineEmits(['ok'])
const activeKey = ref('1')
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const cancelText = ref('取消')
const stationList = ref([])
const visible3=ref(false)
const props = defineProps({
serviceName: {
type: String,
default: ''
}
})
formRules.value = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
identityType: [{ required: true, message: '请选择证件类型', trigger: 'change' }],
identityNo: [{ required: true, message: '请输入证件号码', trigger: 'blur' }],
contact1: [{ validator: validatePhone, trigger: ['blur', 'input'] }, { required: true, message: '请输入联系方式', trigger: 'blur' }],
archive: {
healthStatus: [{ required: true, message: '请选择健康状况', trigger: 'change' }],
serviceStatus: [{ required: true, message: '请选择服务状态', trigger: 'change' }],
homeAreaCodes: [{ required: true, message: '请选择并输入家庭地址', trigger: 'change' }],
homeDetailAddress: [{ required: true, message: '请输入详细地址', trigger: 'change' }],
},
}
const dicsStore = useDicsStore()
//
const selectedServices = ref([])
//
const modalVisible = ref(false)
const loading = ref(false)
//
const serviceList = ref([])
//
const columns = [
{ title: '类型', dataIndex: 'categoryType', key: 'categoryType', align: 'center', width: 100, },
{ title: '分类名称', dataIndex: 'name', key: 'name', align: 'center', width: 180, },
{ title: '项目名称', dataIndex: 'name', key: 'name', align: 'center', },
{ title: '价格', dataIndex: 'price', key: 'price', align: 'center', },
{ title: '简介', dataIndex: 'remark', key: 'remark', align: 'center', },
]
// API
async function fetchServices(){
try {
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceProject
.getProjectList({
pageSize, current,
...searchFormData.value,
})
.catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
listData.value = data
paginationState.total = total
}
} catch (error) {
}
}
//
const rowSelection = {
type: 'checkbox',
selectedRowKeys: ref([]),
onChange: (selectedRowKeys, selectedRows) => {
rowSelection.selectedRowKeys.value = selectedRowKeys
},
getCheckboxProps: (record) => ({
disabled: false
})
}
//
function ceshi(){
console.log(111)
modalVisible.value = true
//
if (serviceList.value.length === 0) {
fetchServices()
}
//
const selectedIds = selectedServices.value.map(s => s.id)
rowSelection.selectedRowKeys.value = selectedIds
}
//
const handleRemove = (item) => {
selectedServices.value = selectedServices.value.filter(s => s.id !== item.id)
// form
form.serviceItems = selectedServices.value.map(s => s.id)
}
//
const handleConfirm = () => {
const selectedRows = serviceList.value.filter(item =>
rowSelection.selectedRowKeys.value.includes(item.id)
)
selectedServices.value = selectedRows
// form
form.serviceItems = selectedRows.map(s => s.id)
modalVisible.value = false
}
//
const handleCancel2 = () => {
modalVisible.value = false
}
/**
* 编辑
*/
handleEdit()
async function handleEdit(record = {}) {
formData.value.name = record.name
try {
showLoading()
const { data, success } = await apis.serviceMenu.getServiceSiteList({ pageSize: 100, current: 1 })
if (!success) {
hideModal()
return
}
stationList.value = data.map(item => ({ id: item.id, name: item.name }))
} catch (error) {
hideModal()
}
}
/**
* 确定
*/
function handleOk() {
formRef.value
.validateFields()
.then(async (values) => {
try {
showLoading()
let params = {
...formData.value,
labels: formData.value.labelsCode ? formData.value.labelsCode.map(item => dicsStore.getDictLabel('Service_Recipient_Category2', item)) : [],
birthDate: dayjs(formData.value.birthDate).format('YYYY-MM-DD')
}
params.archive.idCardPhotos = formData.value.archive.idCardPhotos.length > 0 ? formData.value.archive.idCardPhotos.map(item => spliceUrl(item)) : ['']
params.archive.uploadedDocuments = formData.value.archive.uploadedDocuments.length > 0 ? formData.value.archive.uploadedDocuments.map(item => spliceUrl(item)) : ['']
if (formData.value.governmentPurchasedServiceStartDate.length > 0) {
params.archive.starGovernmentService = dayjs(formData.value.governmentPurchasedServiceStartDate[0]).format('YYYY-MM-DD')
params.archive.endGovernmentService = dayjs(formData.value.governmentPurchasedServiceStartDate[1]).format('YYYY-MM-DD')
}
//
if (params.identityType === '1' && !isValidIdCard(params.identityNo)) {
return message.error('请输入正确的身份证号码')
}
let result = null
switch (modal.value.type) {
case 'create':
result = await apis.serverObj.createItem(params).catch(() => {
throw new Error()
})
console.log('result', result.code)
break
case 'edit':
console.log(params)
result = await apis.serverObj.updateItem(params.id, params).catch(() => {
throw new Error()
})
break
}
hideLoading()
if (config('http.code.success') === result?.code) {
hideModal()
emit('ok')
}
} catch (error) {
hideLoading()
// message.error(error.message)
}
})
.catch(() => {
hideLoading()
})
}
//
const extractBirthDateFromIdCard = () => {
console.log(111)
const { identityNo } = formData.value;
if (!identityNo) {
formData.value.birthDate = '';
return;
}
console.log(getBirthDate(identityNo))
formData.value.birthDate = dayjs(getBirthDate(identityNo));
};
function onAreaChange(value, labels) {
formData.value.archive.homeAreaLabels = [...labels]
}
function onAreaHoldChange(value, labels) {
formData.value.archive.houseAreaLabels = [...labels]
}
function handleGetLng(obj) {
formData.value.lat = obj.lat
formData.value.lag = obj.lng
}
//
const handleCustomRequest = async (options) => {
const { file, onProgress, onSuccess, onError } = options;
try {
const formData = new FormData();
formData.append('file', file);
const { data } = await apis.common.uploadFile(formData);
const fullUrl = config('http.apiBasic') + data;
console.log(fullUrl)
} catch (err) {
message.error('上传失败');
}
};
/**
* 取消
*/
function handleCancel() {
hideModal()
}
/**
* 关闭后
*/
function onAfterClose() {
resetForm()
formData.value.archive = {}
hideLoading()
}
defineExpose({
handleCreate,
handleEdit,
})
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,396 @@
<template>
<a-modal :open="modal.open" :title="modal.title" :width="800" :confirm-loading="modal.confirmLoading"
:after-close="onAfterClose" :cancel-text="cancelText" @ok="handleOk" @cancel="handleCancel">
<a-card>
<a-form ref="formRef" :model="formData" :rules="formRules">
<a-row :gutter="24">
<!-- 姓名 -->
<a-col :span="12">
<a-form-item label="服务对象" name="name">
<a-input v-model:value="formData.name" placeholder="请输入姓名" disabled />
</a-form-item>
</a-col>
<!-- 性别 -->
<a-col :span="12">
<a-form-item label="服务站点" name="stationId">
<a-select v-model:value="formData.stationId">
<a-select-option v-for="item in stationList" :key="item.id" :value="item.id">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<!-- 出生日期 -->
<a-col :span="24">
<div style="margin-bottom: 20px;">
<span style="margin-right: 10px;"><span style="color: red;">*</span> 服务项目:</span>
<!-- 显示已选项目 -->
<a-tag v-for="item in selectedServices" :key="item.id" closable @close="handleRemove(item)">
{{ item.name }}
</a-tag>
<a-tag @click="showModal2" color="#108ee9" style="cursor: pointer;">
添加服务
</a-tag>
</div>
</a-col>
<a-col :span="12">
<a-form-item label="服务费用" name="price">
<a-input-number v-model:value="formData.price" style="width: 100%;"></a-input-number>
</a-form-item>
</a-col>
<template v-if="formData.orderType == '2'">
<a-col :span="12">
<a-form-item label="服务人员" name="servicePersonId">
<a-select v-model:value="formData.servicePersonId">
<a-select-option v-for="item in servicePersonList" :key="item.id" :value="item.id">
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="计划日期" name="planeDate">
<a-range-picker v-model:value="formData.planeDate" placeholder="请选择计划日期" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="计划开始时间" name="plannedStartDate">
<a-time-picker v-model:value="formData.plannedStartDate" format="HH:mm"
style="width: 100%;" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="要求工单时长" name="workDuration">
<a-input-number v-model:value="formData.workDuration">
<template #addonAfter>分钟</template>
</a-input-number>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="服务地址(如修改服务地址,请务必更新地图定位地址)" name="areaCodes">
<AreaCascader v-model:value="formData.areaCodes" @change="onAreaChange" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="详细地址" name="detailAddress">
<a-input v-model:value="formData.detailAddress"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="地理地图定位" name="gps">
<div @click="mapVisible = true">
<span>{{ gps }}</span>
<AimOutlined style="color: #40a9ff;" />
</div>
</a-form-item>
</a-col>
</template>
<a-col :span="24">
<a-form-item label="服务内容" name="content">
<a-input v-model:value="formData.content"></a-input>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
</a-modal>
<a-modal v-model:open="modalVisible" title="选择服务项目" @ok="handleConfirm" @cancel="handleCancel2" okText="确认"
cancelText="取消" :width="600">
<a-table :dataSource="serviceList" :columns="columns" :row-key="record => record.id"
:row-selection="rowSelection" :pagination="false" :loading="loading" size="small">
<template #bodyCell="{ index, column, record }">
<template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template>
</template>
</a-table>
</a-modal>
<a-modal v-model:open="mapVisible" title="选择地址" @ok="mapVisible = false" @cancel="mapVisible = false" okText="确认"
cancelText="取消" :width="600">
<gx-map @handleGetLng="handleGetLng" />
</a-modal>
</template>
<script setup>
import { cloneDeep } from 'lodash-es'
import { ref, computed } from 'vue'
import { config } from '@/config'
import apis from '@/apis'
import { useForm, useModal, usePagination } from '@/hooks'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import { validatePhone, validateEmail, validateIdCard } from '@/utils/validate'
import { getBirthDate, spliceUrl } from '@/utils/util'
import dayjs from 'dayjs'
import { message } from 'ant-design-vue'
import { selectProps } from 'ant-design-vue/es/vc-select'
import { AimOutlined } from '@ant-design/icons-vue'
import GxMap from '@/components/GxMap/index.vue'
const emit = defineEmits(['ok'])
const activeKey = ref('1')
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const { paginationState } = usePagination()
const cancelText = ref('取消')
const servicePersonList = ref([])
const gps = ref('')
const mapVisible = ref(false)
const stationList = ref([])
formRules.value = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
identityType: [{ required: true, message: '请选择证件类型', trigger: 'change' }],
identityNo: [{ required: true, message: '请输入证件号码', trigger: 'blur' }],
contact1: [{ validator: validatePhone, trigger: ['blur', 'input'] }, { required: true, message: '请输入联系方式', trigger: 'blur' }],
planeDate: [{ required: true, message: '请选择计划日期', trigger: ['blur', 'input'] }],
servicePersonId: [{ required: true, message: '请选择服务人员', trigger: ['blur', 'input'] }],
plannedStartDate: [{ required: true, message: '请选择计划开始时间', trigger: ['blur', 'input'] }],
workDuration: [{ required: true, message: '请选择计划日期', trigger: ['blur', 'input'] }],
areaCodes: [{ required: true, message: '请选择服务地址', trigger: ['blur', 'input'] }],
detailAddress: [{ required: true, message: '请输入详细地址', trigger: 'blur' }]
}
const dicsStore = useDicsStore()
//
const selectedServices = ref([])
//
const modalVisible = ref(false)
const loading = ref(false)
//
const serviceList = ref([])
//
const columns = [
{ title: '类型', dataIndex: 'categoryType', key: 'categoryType', align: 'center', width: 100, },
{ title: '分类名称', dataIndex: 'name', key: 'name', align: 'center', width: 180, },
{ title: '项目名称', dataIndex: 'name', key: 'name', align: 'center', },
{ title: '价格', dataIndex: 'price', key: 'price', align: 'center', },
{ title: '简介', dataIndex: 'remark', key: 'remark', align: 'center', },
]
// 1. selectedRowKeys ref
const selectedRowKeys = ref([])
const rowSelection = computed(() => ({
selectedRowKeys: selectedRowKeys.value,
onChange: (newSelectedRowKeys, selectedRows) => {
console.log('selectedRowKeys:', newSelectedRowKeys, 'selectedRows:', selectedRows)
selectedRowKeys.value = newSelectedRowKeys
selectedServices.value = selectedRows
formData.value.price = selectedServices.value.reduce((sum, item) => sum + item.price, 0)
},
getCheckboxProps: (record) => ({
disabled: record.name === 'Disabled User',
name: record.name,
}),
}))
getSeveicePeople()
async function getSeveicePeople() {
try {
const { success, data, total } = await apis.serviceStaffList
.getProjectList({
pageSize: 100,
current: 1,
})
.catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
servicePersonList.value = data.map(item => ({ id: item.id, name: item.name }))
}
} catch (error) {
}
}
function onAreaChange(value, labels) {
formData.value.areaLabels = [...labels]
}
function handleGetLng(obj) {
gps.value = obj.address
formData.value.lat = obj.lat
formData.value.lng = obj.lng
}
//
async function showModal2() {
modalVisible.value = true
//
// if (serviceList.value.length === 0) {
// fetchServices()
// }
//
try {
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceProject
.getProjectList({
pageSize, current,
})
.catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {
serviceList.value = data
paginationState.total = total
if (selectedServices.value.length > 0) {
const selectedIds = selectedServices.value.map(s => s.id)
selectedRowKeys.value = selectedIds
} else {
selectedRowKeys.value = []
}
}
} catch (error) {
}
}
//
const handleRemove = (item) => {
selectedServices.value = selectedServices.value.filter(s => s.id !== item.id)
formData.value.price = selectedServices.value.reduce((sum, item) => sum + item.price, 0)
}
//
const handleConfirm = () => {
modalVisible.value = false
}
//
const handleCancel2 = () => {
modalVisible.value = false
}
/**
* 新建
*/
function handleCreate() {
formData.value.gender = '1'
showModal({
type: 'create',
title: '新建项',
})
}
/**
* 编辑
*/
async function handleEdit(record = {}, type) {
showModal({
type: 'edit',
title: '编辑对象'
})
formData.value.orderType = type, //线2 线1]
formData.value.customerId = record.id
formData.value.name = record.name
formData.value.areaCodes = record.archive.homeAreaCodes
formData.value.areaLabels = record.archive.homeAreaLabels
if (type == '2') {
formData.value.detailAddress = record.archive.homeDetailAddress
gps.value = record.region.join('') + record.archive.homeDetailAddress
formData.value.lat = record.archive.lag
formData.value.lng = record.archive.lat
}
getServiceStation()
}
async function getServiceStation() {
try {
showLoading()
const { success, data, total } = await apis.serviceMenu
.getServiceSiteList({
pageSize: 100,
current: 1,
})
.catch(() => {
throw new Error()
})
hideLoading()
if (config('http.code.success') === success) {
stationList.value = data.map(item => ({ id: item.id, name: item.name }))
}
} catch (error) {
hideLoading()
}
}
/**
* 确定
*/
function handleOk() {
if (!selectedServices.value.length) {
return message.error('请选择服务项目')
}
formRef.value
.validateFields()
.then(async (values) => {
try {
showLoading()
let params = {
...formData.value,
orderingMethod: 'pc'
}
if (formData.value.planeDate && formData.value.planeDate.length > 0) {
params.plannedServiceStartDate = formData.value.planeDate[0]
params.plannedEndDate = formData.value.planeDate[1]
}
params.projects = serviceList.value
let result = null
switch (modal.value.type) {
case 'create':
result = await apis.serverObj.createItem(params).catch(() => {
throw new Error()
})
console.log('result', result.code)
break
case 'edit':
console.log(params)
result = await apis.serverObj.createOrderItem(params).catch(() => {
throw new Error()
})
break
}
hideLoading()
if (config('http.code.success') === true) {
hideModal()
emit('ok')
}
} catch (error) {
hideLoading()
// message.error(error.message)
}
})
.catch(() => {
hideLoading()
})
}
/**
* 取消
*/
function handleCancel() {
selectedServices.value = []
hideModal()
}
/**
* 关闭后
*/
function onAfterClose() {
selectedServices.value = []
resetForm()
hideLoading()
}
defineExpose({
handleCreate,
handleEdit,
})
</script>
<style lang="less" scoped></style>

View File

@ -291,6 +291,9 @@
</template>
<template v-if="column.key === 'governmentPurchasedService'">
<span>{{ record.governmentPurchasedService ? '是' : '' }}</span>
</template>
<template v-if="column.key === 'region'">
<span>{{ record.region&&record.region.join('/')}}</span>
</template>
<template v-if="column.key === 'serviceRecipientCategory'">
<span>{{
@ -302,13 +305,13 @@
<x-action-button @click="$refs.detailRef.handleCreate(record)">
<span>详情</span>
</x-action-button>
<x-action-button @click="checkHandler(record)">
<x-action-button @click="$refs.lineOrderRef.handleEdit(record,'2')">
<span>线下工单</span>
</x-action-button>
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
</x-action-button>
<x-action-button @click="checkHandler(record)">
<x-action-button @click="$refs.lineOrderRef.handleEdit(record,'1')">
<span>线上工单</span>
</x-action-button>
<x-action-button @click="checkHandler(record)">
@ -322,11 +325,16 @@
</a-row>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
<detail ref="detailRef"></detail>
<LineOrder2 ref="lineOrderRef" />
<!-- <a-drawer v-model:open="lineOpen" class="custom-class" width="600" root-class-name="root-class-name" :root-style="{ color: 'blue' }" :title="lineTitle" placement="right">
<LineOrder ref="lineOrderRef" />
</a-drawer> -->
</template>
<script setup>
import { message, Modal } from 'ant-design-vue'
import { onMounted, ref } from 'vue'
import { nextTick, onMounted, ref } from 'vue'
import apis from '@/apis'
import { config } from '@/config'
import { usePagination } from '@/hooks'
@ -334,6 +342,8 @@ import { useI18n } from 'vue-i18n'
import totalImg from '@/assets/imgs/total.png'
import EditDialog from './components/EditDialog.vue'
import detail from './components/detail.vue'
import LineOrder from './components/LineOrder.vue'
import LineOrder2 from './components/LineOrder2.vue'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import NodeTree from '@/components/NodeTree/index.vue'
@ -343,7 +353,9 @@ defineOptions({
})
const totalCount = ref(0) //
const dicsStore = useDicsStore()
const lineOpen = ref(false)
const lineTitle = ref('线下工单')
const serviceName = ref('')
const columns = [
{
title: '序号',
@ -495,7 +507,8 @@ const columns = [
dataIndex: 'region',
key: 'region',
align: 'center',
width: 120,
width: 180,
ellipsis: true,
},
{
title: '详细地址',
@ -503,6 +516,7 @@ const columns = [
key: 'detailedAddress',
align: 'center',
width: 200,
ellipsis: true,
},
{
title: '残疾类型',
@ -563,7 +577,7 @@ const { t } = useI18n() // 解构出t方法
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
const editDialogRef = ref()
const detailRef = ref()
const lineOrderRef = ref()
onMounted(() => {
searchFormData.value.serviceNodeIds = dicsStore.orgTree[0].value
@ -693,7 +707,11 @@ function handleResetSearch() {
async function onOk() {
await getPageList()
}
function lineOrder(record) {
lineOpen.value = true;
lineTitle.value = '线下工单';
}
</script>
<style lang="less" scoped></style>

View File

@ -1,14 +1,34 @@
<template>
<a-modal :open="modal.open" :title="modal.title" :width="600" :confirm-loading="modal.confirmLoading"
<a-modal :open="modal.open" :title="modal.title" :width="800" :confirm-loading="modal.confirmLoading"
:after-close="onAfterClose" :cancel-text="cancelText" @ok="handleOk" @cancel="handleCancel">
<a-card>
<a-form ref="formRef" :model="formData" :rules="formRules">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="姓名" name="name">
<a-form-item label="所属服务站点" name="stationId">
<a-select v-model:value="formData.stationId" allowClear>
<a-select-option v-for="item in stationList" :key="item.id"
:value="item.id">{{
item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="服务人员姓名" name="name">
<a-input v-model:value="formData.name" placeholder="请输入姓名" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="身份证号" name="idCard">
<a-input v-model:value="formData.idCard" placeholder="请输入证件号码"
@change="extractBirthDateFromIdCard" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="出生日期" name="birthDate2">
<a-input v-model:value="formData.birthDate2" placeholder="根据身份证号码自动识别" disabled />
</a-form-item>
</a-col>
<!-- 性别 -->
<a-col :span="12">
<a-form-item label="性别" name="gender">
@ -19,21 +39,13 @@
</a-form-item>
</a-col>
<!-- 证件号码 -->
<a-col :span="12">
<a-form-item label="身份证号" name="idCard">
<a-input v-model:value="formData.idCard" placeholder="请输入证件号码" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="电话" name="phone">
<a-input v-model:value="formData.phone" placeholder="请输入电话" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="电话" name="phone">
<a-input v-model:value="formData.phone" placeholder="请输入电话" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="护理人员类型" name="serviceType">
<a-select v-model:value="formData.serviceType" allowClear>
@ -44,9 +56,32 @@
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="护理人员状态" name="status">
<a-select v-model:value="formData.status" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.STAFF_STATUS" :key="item.dval"
<a-form-item label="资格证照名称" name="qualificationName">
<a-input v-model:value="formData.qualificationName" placeholder="请输入资格证照名称" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="资格证照等级" name="qualificationLV">
<a-select v-model:value="formData.qualificationLV" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.QUA_LV" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="参保情况" name="insuranceStatus">
<a-select v-model:value="formData.insuranceStatus" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.INSURANCE_STATUS" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="学历" name="education">
<a-select v-model:value="formData.education" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.EDUCATION_LEVEL" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
@ -61,16 +96,89 @@
</a-select>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="所属服务组织" name="stationLables">
<node-tree v-model:value="formData.stationLables" />
<a-col :span="12">
<a-form-item label="负责区域" name="sAreaCodes">
<AreaCascader v-model:value="formData.sAreaCodes" @change="onAreaChange" />
</a-form-item>
</a-col>
<!-- <a-col :span="8">
<a-form-item label="组织所在区域" name="areaLabels">
<node-tree v-model:value="formData.areaLabels" />
<a-col :span="12">
<a-form-item label="提成比例" name="commissionRate">
<a-input-number v-model:value="formData.commissionRate" placeholder="请输入提成比例">
<template #addonAfter>
<span>%</span>
</template>
</a-input-number>
</a-form-item>
</a-col> -->
</a-col>
<a-col :span="12">
<a-form-item label="入职日期" name="joinAt">
<a-date-picker v-model:value="formData.joinAt" placeholder="请选择入职日期" style="width: 100%;" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="资格证照注册号" name="qualificationNo">
<a-input v-model:value="formData.qualificationNo" placeholder="请输入资格证照注册号" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="劳动合同期限" name="laborContract">
<a-range-picker v-model:value="formData.laborContract" placeholder="请选择劳动合同期限" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="星级评价等级" name="starLv">
<a-select v-model:value="formData.starLv" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.START_LV" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="开户行名称" name="bankName">
<a-input v-model:value="formData.bankName" placeholder="请输入开户行名称" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="银行卡号" name="bankNo">
<a-input v-model:value="formData.bankNo" placeholder="请输入银行卡号" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="补贴类型" name="subsidyType">
<a-select v-model:value="formData.subsidyType" allowClear>
<a-select-option v-for="item in dicsStore.dictOptions.SUBSIDY_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="家庭地址" name="areaCodes">
<AreaCascader v-model:value="formData.areaCodes" @change="onAreaChange2" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="家庭详细地址" name="address">
<a-input v-model:value="formData.address" placeholder="请输入家庭详细地址"></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="备注" name="remark">
<a-textarea v-model:value="formData.remark" placeholder="请输入备注" :rows="4"></a-textarea>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="证件照片" name="imgs">
<gx-upload v-model="formData.imgs" accept-types=".jpg,.png,.webp" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="附件" name="attachments">
<gx-upload v-model="formData.attachments" accept-types=".jpg,.png,.webp,.xlsx,.docx,.doc" />
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
@ -87,33 +195,84 @@ import { useForm, useModal } from '@/hooks'
import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import NodeTree from '@/components/NodeTree/index.vue'
import dayjs from 'dayjs'
import { getBirthDate, spliceUrl } from '@/utils/util'
import { validatePhone, validateEmail, validateIdCard } from '@/utils/validate'
const emit = defineEmits(['ok'])
const activeKey = ref('1')
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const cancelText = ref('取消')
const dicsStore = useDicsStore()
const stationList=ref([])
formRules.value={
stationId: [{ required: true, message: '请选择服务组织',trigger: ['blur','change']}],
name: [{ required: true, message: '请输入姓名',trigger: 'blur' }],
idCard: [{ validator: validateIdCard, trigger: ['blur', 'input'] }, { required: true, message: '请输入联系方式', trigger: 'blur' }],
phone: [{ validator: validatePhone, trigger: ['blur', 'input'] }, { required: true, message: '请输入联系方式', trigger: 'blur' }],
serviceType: [{ required: true, message: '请选择护理人员类型',trigger: ['blur','change']}],
insuranceStatus: [{ required: true, message: '请选择参保情况',trigger: ['blur','change']}],
}
/**
* 新建
*/
function handleCreate() {
formData.value.gender='1'
showModal({
type: 'create',
title: '新增服务人员',
})
}
getStationList()
async function getStationList(){
try {
showLoading()
const { success, data, total } = await apis.serviceMenu
.getServiceSiteList({
pageSize:100,
current: 1,
})
.catch(() => {
throw new Error()
})
hideLoading()
if (config('http.code.success') === success) {
//type80about
stationList.value = data.map(item=>({id:item.id,name:item.name}))
}
} catch (error) {
hideLoading()
}
}
/**
* 编辑
*/
function handleEdit(record = {}) {
showModal({
type: 'edit',
title: '编辑项',
})
formRecord.value = record
formData.value = cloneDeep(record)
async function handleEdit(record = {}) {
try {
showModal({
type: 'edit',
title: '编辑项',
})
const { data, success } = await apis.serviceStaffList.getItem(record.id).catch()
if (!success) {
hideModal()
return
}
formRecord.value = data
if (formData.value.joinAt) {
formData.value.joinAt = dayjs(formData.value.joinAt)
}
if (formData.value.laborContractStartAt && formData.value.laborContractEndAt) {
formData.value.laborContract = [dayjs(formData.value.laborContractStartAt), dayjs(formData.value.laborContractEndAt)]
}
formData.value.imgs = (data.imgs && data.imgs.length > 0) ? data.imgs.map(item => config('http.apiBasic') + item) : []
formData.value.attachments = (data.attachments && data.attachments.length > 0) ? data.attachments.map(item => config('http.apiBasic') + item) : []
formData.value.commissionRate=formData.value.commissionRate??formData.value.commissionRate*100
formData.value.birthDate2=dayjs(data.birthDate).format('YYYY-DD-MM')
} catch (error) {
}
}
@ -126,28 +285,39 @@ function handleOk() {
.then(async (values) => {
try {
showLoading()
const params = {
let params = {
...formData.value,
birthDate:new Date(formData.value.birthDate)
}
if (formData.value.laborContract && formData.value.laborContract.length > 0) {
params.laborContractStartAt = formData.value.laborContract[0]
params.laborContractEndAt = formData.value.laborContract[1]
}
params.imgs = (formData.value.imgs&&formData.value.imgs.length) > 0 ? formData.value.imgs.map(item => spliceUrl(item)) : ['']
params.attachments = (formData.value.attachments&&formData.value.attachments.length) > 0 ? formData.value.attachments.map(item => spliceUrl(item)) : ['']
params.commissionRate=formData.value.commissionRate??formData.value.commissionRate/100
console.log(params)
let result = null
switch (modal.value.type) {
case 'create':
result = await apis.serverObj.createItem(params).catch(() => {
result = await apis.serviceStaffList.createItem(params).catch(() => {
throw new Error()
})
break
case 'edit':
result = await apis.serverObj.updateItem(params).catch(() => {
result = await apis.serviceStaffList.updateItem(params).catch(() => {
throw new Error()
})
break
}
hideLoading()
if (config('http.code.success') === result?.code) {
if (config('http.code.success') === true) {
hideModal()
emit('ok')
}
} catch (error) {
console.log(error.message)
hideLoading()
}
})
@ -155,7 +325,24 @@ function handleOk() {
hideLoading()
})
}
//
const extractBirthDateFromIdCard = () => {
console.log(111)
const { idCard } = formData.value;
if (!idCard) {
formData.value.birthDate = '';
return;
}
console.log(getBirthDate(idCard))
formData.value.birthDate2=getBirthDate(idCard)
formData.value.birthDate =new Date(getBirthDate(idCard));
}
function onAreaChange(value, labels) {
formData.value.sAreaLabels = [...labels]
}
function onAreaChange2(value, labels) {
formData.value.areaLabels = [...labels]
}
/**
* 取消
*/

View File

@ -78,6 +78,14 @@
<template v-if="column.key === 'serialNumber'">
<span>{{ index + 1 }}</span>
</template>
<template v-if="column.key === 'gender'">
<span v-if="record.gender=='1'"></span>
<span v-else></span>
</template>
<template v-if="column.key === 'serviceType'">
<span>{{ dicsStore.getDictLabel('STAFF_TYPE', record.serviceType) }}</span>
</template>
<template v-if="'action' === column.key">
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
@ -170,14 +178,6 @@ const columns = [
align: 'center',
width: 120,
},
// --- ---
{
title: '护理人员类型',
dataIndex: 'serviceType',
key: 'serviceType',
align: 'center',
width: 130,
},
{
title: '所属服务组织',
dataIndex: 'stationName',

View File

@ -175,7 +175,7 @@
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz"
integrity sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==
"@babel/runtime@^7.10.5":
"@babel/runtime@^7.10.5", "@babel/runtime@^7.5.5":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz"
integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==
@ -302,6 +302,51 @@
resolved "https://registry.npmmirror.com/@intlify/shared/-/shared-9.14.4.tgz"
integrity sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==
"@jiaminghi/bezier-curve@*":
version "0.0.9"
resolved "https://registry.npmmirror.com/@jiaminghi/bezier-curve/-/bezier-curve-0.0.9.tgz"
integrity sha512-u9xJPOEl6Dri2E9FfmJoGxYQY7vYJkURNX04Vj64tdi535tPrpkuf9Sm0lNr3QTKdHQh0DdNRsaa62FLQNQEEw==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/c-render@^0.4.3":
version "0.4.3"
resolved "https://registry.npmmirror.com/@jiaminghi/c-render/-/c-render-0.4.3.tgz"
integrity sha512-FJfzj5hGj7MLqqqI2D7vEzHKbQ1Ynnn7PJKgzsjXaZpJzTqs2Yw5OSeZnm6l7Qj7jyPAP53lFvEQNH4o4j6s+Q==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/bezier-curve" "*"
"@jiaminghi/color" "*"
"@jiaminghi/transition" "*"
"@jiaminghi/charts@*":
version "0.2.18"
resolved "https://registry.npmmirror.com/@jiaminghi/charts/-/charts-0.2.18.tgz"
integrity sha512-K+HXaOOeWG9OOY1VG6M4mBreeeIAPhb9X+khG651AbnwEwL6G2UtcAQ8GWCq6GzhczcLwwhIhuaHqRygwHC0sA==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/c-render" "^0.4.3"
"@jiaminghi/color@*":
version "1.1.3"
resolved "https://registry.npmmirror.com/@jiaminghi/color/-/color-1.1.3.tgz"
integrity sha512-ZY3hdorgODk4OSTbxyXBPxAxHPIVf9rPlKJyK1C1db46a50J0reFKpAvfZG8zMG3lvM60IR7Qawgcu4ZDO3+Hg==
"@jiaminghi/data-view@^2.10.0":
version "2.10.0"
resolved "https://registry.npmmirror.com/@jiaminghi/data-view/-/data-view-2.10.0.tgz"
integrity sha512-Cud2MTiMcqc5k2KWabR/svuVQmXHANqURo+yj40370/LdI/gyUJ6LG203hWXEnT1nMCeiv/SLVmxv3PXLScCeA==
dependencies:
"@babel/runtime" "^7.5.5"
"@jiaminghi/charts" "*"
"@jiaminghi/transition@*":
version "1.1.11"
resolved "https://registry.npmmirror.com/@jiaminghi/transition/-/transition-1.1.11.tgz"
integrity sha512-owBggipoHMikDHHDW5Gc7RZYlVuvxHADiU4bxfjBVkHDAmmck+fCkm46n2JzC3j33hWvP9nSCAeh37t6stgWeg==
dependencies:
"@babel/runtime" "^7.5.5"
"@jridgewell/sourcemap-codec@^1.4.13":
version "1.4.15"
resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"