This commit is contained in:
qiuyuan 2025-11-14 09:33:25 +08:00
commit 9feb188430
20 changed files with 3094 additions and 5108 deletions

View File

@ -12,7 +12,8 @@ VITE_ROUTER_BASE=/
VITE_ROUTER_HISTORY=hash
# api
VITE_API_BASIC='http://10.10.1.39:8040'
# VITE_API_BASIC='http://10.10.1.39:8040'
VITE_API_BASIC='http://115.239.217.220:8021'
VITE_API_UPLOAD='http://115.239.217.220:9458'
VITE_API_HTTP=/api/v1/
# storage

6823
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@
"xy-storage": "^3.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.3.1",
"@vitejs/plugin-vue": "^5.0.0",
"eslint": "^8.47.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
@ -60,7 +60,7 @@
"less": "^4.2.0",
"lint-staged": "^14.0.0",
"rollup-plugin-visualizer": "^5.9.2",
"vite": "^4.4.9",
"vite": "^5.0.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-progress": "^0.0.7",

View File

@ -41,6 +41,7 @@ const theme = ref({
background-repeat: no-repeat;
background-color: transparent;
padding: 20px;
color: #ffffff;
}
.bottom-center .amap-info-sharp:after {

View File

@ -13,4 +13,12 @@ export const updateItem = (params) => request.basic.put(`/api/v1/service-people/
// 删除数据
export const delItem = (id) => request.basic.delete(`/api/v1/service-people/${id}`)
//获取服务项目树状数据
export const getTreeData=(params)=>request.basic.get('/api/v1/service-projects/category_project',params)
//绑定服务项目
export const createProject=(params)=>request.basic.post('/api/v1/service-person-projects/many',params)
//获取服务人员绑定的服务项目
export const getProject=(params)=>request.basic.get('/api/v1/service-person-projects',params)

View File

@ -1,18 +1,23 @@
<!-- AreaCascader.vue -->
<template>
<a-cascader v-model:value="modelValue" :options="options" :load-data="loadData" :placeholder="placeholder"
<a-cascader v-model:value="innerValue" :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, nextTick, defineModel, onMounted,defineExpose } from 'vue';
import { ref, watch, nextTick, onMounted, defineProps, defineEmits, defineExpose } from 'vue';
import apis from '@/apis';
import { useDicsStore } from '@/store';
const dicsStore = useDicsStore();
const modelValue = defineModel();
// 🔸 使 defineProps v-model props
const props = defineProps({
modelValue: {
type: String,
default: ''
},
placeholder: { type: String, default: '请选择省市区' },
style: { type: Object, default: () => ({ width: '100%' }) },
disabled: { type: Boolean, default: false },
@ -23,26 +28,50 @@ const props = defineProps({
type: Object,
default: () => ({
label: 'label',
value: 'code',
// children: 'children' // children
value: 'code'
})
}
});
const emit = defineEmits(['change']);
const options = ref([]);
// 🔸 emit v-model change
const emit = defineEmits(['update:modelValue', 'change']);
// 🔁 store
// 🔸 a-cascader v-model:value
const innerValue = ref([]);
// 🔁 modelValue
watch(
() => dicsStore.provinceOptions,
() => props.modelValue,
(newVal) => {
if (newVal && newVal.length > 0) {
options.value = newVal;
if (newVal && typeof newVal === 'string') {
const codes = newVal.split(',').filter(Boolean);
innerValue.value = codes;
// options
if (options.value.length > 0 && codes.length > 1) {
initData(codes);
}
} else {
innerValue.value = [];
}
},
{ immediate: true }
);
// 🔁 store
const options = ref([]);
watch(
() => dicsStore.provinceOptions,
(newVal) => {
if (newVal && newVal.length > 0) {
options.value = newVal;
//
if (innerValue.value.length > 1) {
initData([...innerValue.value]);
}
}
},
{ immediate: true }
);
// 🔍
function findNodeInOptions(options, code) {
@ -55,37 +84,14 @@ function findNodeInOptions(options, code) {
}
return null;
}
async function initData(codes){
//
for (let i = 1; i < codes.length; i++) {
const parentCode = codes[i - 1];
// const currentCode = val[i];
//
let targetNode;
if (i === 1) {
// options
targetNode = options.value.find(opt => opt.code === parentCode);
} else {
//
targetNode = findNodeInOptions(options.value, parentCode);
}
if (targetNode && !targetNode.children) {
// loadData
await loadData([targetNode]);
}
//
await nextTick();
}
}
// 🌐
const loadData = async (selectedOptions) => {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
try {
const parentId = targetOption.id || targetOption.code; // id code
const parentId = targetOption.id || targetOption.code;
const response = await apis.common.getAreaList({
current: 1,
pageSize: 100,
@ -98,16 +104,15 @@ const loadData = async (selectedOptions) => {
const children = response.data.map(item => ({
...item,
isLeaf: !item.hasChild,
label: item.label || item.name, //
label: item.label || item.name,
value: item.code
}));
targetOption.children = children;
} else {
targetOption.children = [];
}
//
//
options.value = [...options.value];
} catch (error) {
console.error('加载子节点失败:', error);
@ -118,8 +123,38 @@ const loadData = async (selectedOptions) => {
// 📣
const handleChange = (value, selectedOptions) => {
console.log(value)
// value code ['110000', '110100', '110101']
const fullCode = value ? value.join(',') : '';
innerValue.value = value || [];
// v-model
emit('update:modelValue', fullCode);
// change code label
emit('change', value, selectedOptions?.map(opt => opt.label) || []);
};
defineExpose({initData})
// 🧩
async function initData(codes) {
if (!codes || codes.length <= 1) return;
for (let i = 1; i < codes.length; i++) {
const parentCode = codes[i - 1];
let targetNode;
if (i === 1) {
targetNode = options.value.find(opt => opt.code === parentCode);
} else {
targetNode = findNodeInOptions(options.value, parentCode);
}
if (targetNode && !targetNode.children) {
await loadData([targetNode]);
}
await nextTick();
}
}
// 💡
defineExpose({ initData });
</script>

View File

@ -126,7 +126,7 @@ const handleMapClick = (e) => {
content: `<div style="padding:10px;min-width:200px;">
<div style="font-weight:bold;margin-bottom:5px;">点击位置</div>
<div>${address}</div>
<div style="margin-top:8px;color:#666;">
<div style="margin-top:8px;color:#fff;">
<div>经度: ${lng.toFixed(6)}</div>
<div>纬度: ${lat.toFixed(6)}</div>
</div>

View File

@ -1,6 +1,6 @@
<!-- @/components/TreeSelect.vue -->
<template>
<a-tree-select v-model:value="modelValue" show-search :style="{ width: width }"
<a-tree-select v-model:value="innerValue" show-search :style="{ width: width }"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" :placeholder="placeholder" :allow-clear="allowClear"
:tree-default-expand-all="defaultExpandAll" :tree-data="localTreeData" :tree-node-filter-prop="filterProp"
:disabled="disabled" :loading="loading" @change="handleChange" @search="handleSearch" @focus="handleFocus"
@ -10,91 +10,110 @@
</template>
<script setup>
import { ref, watch, onMounted,defineModel } from 'vue'
import { useDicsStore } from '@/store'
const dicsStore = useDicsStore()
const modelValue = defineModel();
import { ref, watch, onMounted, defineProps, defineEmits } from 'vue';
import { useDicsStore } from '@/store';
const dicsStore = useDicsStore();
// 🔸 props v-model modelValue
const props = defineProps({
allowClear:{
type:Boolean,
default:false
},
width: {
type: String,
default: '100%'
},
placeholder: {
type: String,
default: '请选择节点'
},
filterProp: {
type: String,
default: 'label'
},
defaultExpandAll: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
// store
useStore: {
type: Boolean,
default: true
}
})
modelValue: {
type: [String, Number, Array], // a-tree-select string/array
default: ''
},
allowClear: {
type: Boolean,
default: false
},
width: {
type: String,
default: '100%'
},
placeholder: {
type: String,
default: '请选择节点'
},
filterProp: {
type: String,
default: 'label'
},
defaultExpandAll: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
},
useStore: {
type: Boolean,
default: true
}
});
const emit = defineEmits(['update:modelValue', 'change', 'search', 'focus', 'blur'])
// 🔸 emits
const emit = defineEmits(['update:modelValue', 'change', 'search', 'focus', 'blur']);
// 🔸 a-tree-select v-model:value
const innerValue = ref(props.modelValue);
const localTreeData = ref([])
const loading = ref(false)
// store
// 🔁 modelValue
watch(
() => dicsStore.orgTree,
(newVal) => {
if (newVal?.length > 0) {
localTreeData.value = newVal
console.log('localTreeData',localTreeData.value)
// modelValue.value=localTreeData.value[0].value
loading.value = false
}
},
{ immediate: true }
)
() => props.modelValue,
(newVal) => {
innerValue.value = newVal;
}
);
// store
onMounted(async () => {
if (props.useStore) {
if (dicsStore.orgTree.length === 0 && !loading.value) {
loading.value = true
try {
await dicsStore.loadOrgTree()
// watch
} catch (error) {
loading.value = false
}
}
// 🔁 store
const localTreeData = ref([]);
const loading = ref(false);
watch(
() => dicsStore.orgTree,
(newVal) => {
if (Array.isArray(newVal) && newVal.length > 0) {
localTreeData.value = newVal;
loading.value = false;
}
})
},
{ immediate: true }
);
// 📥
onMounted(async () => {
if (props.useStore) {
if (dicsStore.orgTree.length === 0 && !loading.value) {
loading.value = true;
try {
await dicsStore.loadOrgTree();
// watch localTreeData
} catch (error) {
console.error('加载组织树失败:', error);
loading.value = false;
}
}
}
});
// 📤
const handleChange = (value, label, extra) => {
emit('change', value, label, extra)
}
innerValue.value = value;
emit('update:modelValue', value); // v-model
emit('change', value, label, extra);
};
// 🔍
const handleSearch = (value) => {
console.log(value)
emit('search', value)
}
emit('search', value);
};
// 💡 /
const handleFocus = () => {
emit('focus')
}
emit('focus');
};
const handleBlur = () => {
emit('blur')
}
emit('blur');
};
</script>

View File

@ -7,23 +7,30 @@
</template>
<script setup>
import { ref,defineModel } from 'vue'
import { ref, watch } from 'vue'
import apis from '@/apis'
// 使 defineModel
// { currentOrg: String, onUpdateCurrentOrg: Function }
// ref
const model = defineModel('currentOrg', { type: String, default: '' })
const model = ref(props.currentOrg)
// prop
const props = defineProps({
defaultOpen: {
type: Boolean,
default: false
}
},
currentOrg: {
type: String,
default: ''
},
})
const emit = defineEmits(['change']) // change
// prop currentOrg
watch(() => props.currentOrg, (newVal) => {
model.value = newVal
})
const emit = defineEmits(['update:currentOrg', 'change']) // change
//
const stationList = ref([])
@ -44,7 +51,8 @@ async function getData() {
// change
function handleChange(e) {
// model.value
model.value = e
emit('update:currentOrg', e) // v-model
emit('change', e)
}
</script>

View File

@ -1,12 +1,7 @@
<template>
<div
class="brand"
:class="cpClass"
:style="cpStyle">
<img
alt=""
:src="config('app.logo')" />
<h1>{{ config('app.title') }}</h1>
<div class="brand" :class="cpClass" :style="cpStyle">
<!-- <img alt="" src="/public/logo-hahayun.png" /> -->
<h1 style="color:#7babdb">{{ Title }}</h1>
</div>
</template>
@ -15,7 +10,7 @@ import { storeToRefs } from 'pinia'
import { computed } from 'vue'
import { config } from '@/config'
import { useAppStore } from '@/store'
import storage from '@/utils/storage'
defineOptions({
name: 'Brand',
})
@ -49,6 +44,10 @@ const cpStyle = computed(() => {
height: `${appConfig.value.headerHeight}px`,
}
})
const Title = computed(() => {
const platForm = storage.local.getItem('platform')
return platForm == 'jianguan' ? '智慧养老居家监管平台' : platForm == 'yunying' ? '智慧养老居家运营平台' : '智慧养老居家呼叫平台'
})
</script>
<style lang="less" scoped>

View File

@ -46,17 +46,17 @@ export default [
permission: '*',
},
},
{
path: 'institution',
name: 'institution',
component: 'serverObj/institution/index.vue',
meta: {
title: '机构服务对象列表',
isMenu: true,
keepAlive: true,
permission: '*',
},
},
// {
// path: 'institution',
// name: 'institution',
// component: 'serverObj/institution/index.vue',
// meta: {
// title: '机构服务对象列表',
// isMenu: true,
// keepAlive: true,
// permission: '*',
// },
// },
{
path: 'toBeInstitution',
name: 'toBeInstitution',

View File

@ -4,7 +4,7 @@
<a-form :model="searchFormData" layout="inline" labelAlign="left">
<a-row :gutter="[24, 24]">
<!-- 所在区域 -->
<a-col :span="8" v-if="platForm !== 'yunying'">
<a-col :span="8" v-if="platForm !== 'yunying'">
<a-form-item label="所属服务组织" name="station">
<node-tree v-model:value="searchFormData.station" />
</a-form-item>
@ -78,7 +78,7 @@
<template v-if="column.key === 'serialNumber'">
<span>{{ index + 1 }}</span>
</template>
<template v-if="column.key === 'workType'">
<template v-if="column.key === 'workType'">
<span>{{ dicsStore.getDictLabel('USE_TYPE', record.workType) }}</span>
</template>
<template v-if="column.key === 'gender'">
@ -86,8 +86,7 @@
<span v-else></span>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status == '1'" color="green">启用</a-tag>
<a-tag v-else color="red">禁用</a-tag>
<a-tag>{{ dicsStore.getDictLabel('STAFF_STATUS', record.status) }}</a-tag>
</template>
<template v-if="column.key === 'serviceType'">
<span>{{ dicsStore.getDictLabel('STAFF_TYPE', record.serviceType) }}</span>
@ -100,11 +99,13 @@
<x-action-button @click="$refs.detailRef.handleEdit(record)">
<span>详情</span>
</x-action-button>
<x-action-button @click="$refs.editDialogRef.handleEdit(record)" v-if="platForm==='yunying'">
<x-action-button @click="treeHandleEdit(record.id)" v-if="platForm === 'yunying'">
<span>服务项目</span>
</x-action-button>
<x-action-button @click="$refs.editDialogRef.handleEdit(record)" v-if="platForm==='yunying'">
<span>停用</span>
<x-action-button @click="handleStop(record)"
v-if="platForm === 'yunying' && (record.status == '1' || record.status == '4')">
<span v-if="record.status === '1'">停用</span>
<span v-if="record.status === '4'">启用</span>
</x-action-button>
<x-action-button @click="handleDelete(record)">
<span style="color: #ff4d4f;">删除</span>
@ -117,6 +118,19 @@
</a-row>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
<detail ref="detailRef"></detail>
<a-modal v-model:open="treeOpen" title="绑定服务项目" @ok="handleOk">
<a-card>
<a-spin :spinning="spinning">
<a-tree v-model:expandedKeys="expandedKeys" v-model:selectedKeys="selectedKeys"
v-model:checkedKeys="checkedKeys" checkable :tree-data="treeData" @check="onCheck">
<template #title="{ title, key }">
<span v-if="key === '0-0-1-0'" style="color: #1890ff">{{ title }}</span>
<template v-else>{{ title }}</template>
</template>
</a-tree>
</a-spin>
</a-card>
</a-modal>
</template>
<script setup>
@ -133,9 +147,17 @@ import detail from './components/detail.vue'
import dayjs from 'dayjs'
import NodeTree from '@/components/NodeTree/index.vue'
import storage from '@/utils/storage'
import { getBirthDate, spliceUrl } from '@/utils/util'
defineOptions({
name: 'allocation',
})
const currentId = ref('')
const spinning = ref(false)
const expandedKeys = ref([])
const selectedKeys = ref([])
const checkedKeys = ref([])
const treeData = ref([])
const treeOpen = ref(false)
const dicsStore = useDicsStore()
const platForm = storage.local.getItem('platform')
const columns = [
@ -228,6 +250,7 @@ getPageList()
async function getPageList() {
try {
loading.value = true
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceStaffList
.getProjectList({
@ -244,32 +267,126 @@ async function getPageList() {
if (config('http.code.success') === success) {
listData.value = data
paginationState.total = total
loading.value = false
getServerProject()
}
} catch (error) {
loading.value = false
}
}
//
function isLeafNode(nodeKey, data = treeData.value) {
for (const item of data) {
if (item.key === nodeKey) {
return !item.children || item.children.length === 0;
}
if (item.children && item.children.length > 0) {
const found = isLeafNode(nodeKey, item.children);
if (found !== null) return found;
}
}
return null; //
}
//
function getAllLeafKeys(data) {
let leaves = [];
data.forEach(item => {
if (!item.children || item.children.length === 0) {
leaves.push(item.key);
} else {
leaves = leaves.concat(getAllLeafKeys(item.children));
}
});
return leaves;
}
//
const onCheck = (checkedKeysObj, info) => {
console.log(checkedKeysObj)
// const { checked, halfChecked } = checkedKeysObj;
//
const leafCheckedKeys = checkedKeysObj.filter(key => {
return isLeafNode(key) === true;
});
// checkedKeys
checkedKeys.value = leafCheckedKeys;
};
/**核销 */
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()
}
},
const getServerProject = async (id) => {
try {
currentId.value = id
const { data, success } = await apis.serviceStaffList.getTreeData({ categoryType: '1' })
if (success) {
treeData.value = transformCategories(data)
}
} catch (error) {
console.log(error.msg)
}
}
async function treeHandleEdit(id){
try {
currentId.value=id
spinning.value=true
treeOpen.value = true
const {data,success}=await apis.serviceStaffList.getProject({current:1,pageSize:99,servicePersonId:id})
if (success) {
checkedKeys.value=data.map(item=>item.projectId)
console.log(selectedKeys.value)
}
spinning.value=false
} catch (error) {
spinning.value=false
}
}
function transformCategories(data) {
return data.map(category => ({
key: category.categoryId,
title: category.categoryName,
children: category.projects.map(project => ({
key: project.id,
title: project.name
}))
}));
}
const handleOk = async () => {
try {
const params = { servicePersonId: currentId.value, projectIds: checkedKeys.value }
const {success} = await apis.serviceStaffList.createProject(params)
if(success){
message.success('绑定成功')
treeOpen.value=false
checkedKeys.value=[]
}
} catch (error) {
console.log(error)
}
}
const handleStop = async (record) => {
let params = {
...record,
birthDay: record.birthDate2
}
if (record.laborContract && record.laborContract.length > 0) {
params.laborContractStartAt = record.laborContract[0]
params.laborContractEndAt = record.laborContract[1]
}
params.imgs = (record.imgs && record.imgs.length) > 0 ? record.imgs.map(item => spliceUrl(item)) : []
params.attachments = (record.attachments && record.attachments.length) > 0 ? record.attachments.map(item => spliceUrl(item)) : []
params.commissionRate = record.commissionRate ?? record.commissionRate / 100
params.status = record.status == '4' ? '1' : '4'
console.log(params)
const { success } = await apis.serviceStaffList.updateItem(params).catch(() => {
throw new Error()
})
if (success) {
getPageList()
}
}
/**
* 删除

View File

@ -5,8 +5,8 @@
<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-form-item label="类型" name="categoryType" >
<a-select v-model:value="formData.categoryType" allowClear :disabled="categoryDisabled">
<a-select-option v-for="item in dicsStore.dictOptions.PROJECT_TYPE" :key="item.dval"
:value="item.dval">{{
item.introduction }}</a-select-option>
@ -138,6 +138,7 @@ const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { formRecord, formData, formRef, formRules, resetForm } = useForm()
const cancelText = ref('取消')
const dicsStore = useDicsStore()
const categoryDisabled=ref(false)
formRules.value = {
categoryType: [{ required: true, message: '请选择类型', trigger: ['blur', 'change'] }],
categoryId: [{ required: true, message: '请选择类型', trigger: ['blur', 'change'] }],
@ -158,6 +159,7 @@ function handleCreate() {
type: 'create',
title: '新增',
})
categoryDisabled.value=false
formData.value = {
priceUnit: '元/次',
frequencyUnit: '元/次',
@ -170,8 +172,9 @@ function handleCreate() {
function handleEdit(record = {}) {
showModal({
type: 'edit',
title: '编辑',
title: '编辑11',
})
categoryDisabled.value=true
formRecord.value = record
formData.value = cloneDeep(record)
}

View File

@ -14,7 +14,7 @@
<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">{{
<a-select-option v-for="item in categoryList" :key="item.id" :value="item.id">{{
item.name }}</a-select-option>
</a-select>
</a-form-item>
@ -50,11 +50,13 @@
<template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template>
<template v-if="column.key === 'categoryId'">
<span>{{categoryList.find(item=>item.id==record.categoryId).name}}</span>
</template>
<template v-if="column.key === 'price'">
<span>{{ record.price + record.frequencyUnit }}</span>
</template>
<template v-if="'action' === column.key">
<x-action-button @click="$refs.editDialogRef.handleEdit(record)">
<span>编辑</span>
@ -82,15 +84,15 @@ defineOptions({
name: 'serverProject',
})
const dicsStore = useDicsStore()
const categoryList=ref([])
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: 'categoryId', key: 'categoryId', align: 'center', width: 180, },
{ title: '项目名称', dataIndex: 'name', key: 'name', align: 'center', },
{ title: '价格', dataIndex: 'price', key: 'price', align: 'center', },
{ title: '简介', dataIndex: 'content', key: 'content', align: 'center', },
{ title: '操作', dataIndex: 'action', key: 'action', align: 'center', width: 120, fixed: 'right', }
];
const { t } = useI18n() // t
@ -104,14 +106,14 @@ async function getCategoriesAll() {
console.log(111)
const { success, data, total } = await apis.projectType
.getProjectListAll({
pageSize:100, current:1,
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}))
categoryList.value = data.map(item => ({ id: item.id, name: item.name }))
}
} catch (error) {

View File

@ -564,51 +564,54 @@ async function handleEdit(record = {}) {
function isValidIdCard(value) {
if (!value || typeof value !== 'string') return false;
const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{18}X$)/i;
if (!idCardRegex.test(value)) return false;
//
const id = value.trim().toUpperCase();
// 18
if (value.length === 18) {
const Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
const Vi = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
// 151817 + X
const reg = /^(\d{15}|\d{17}[\dX])$/;
if (!reg.test(id)) return false;
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += parseInt(value[i], 10) * Wi[i];
}
const checkCode = Vi[sum % 11];
if (checkCode !== value[17].toUpperCase()) {
return false;
}
}
const len = id.length;
//
let year, month, day;
if (value.length === 15) {
year = '19' + value.substring(6, 8);
month = value.substring(8, 10);
day = value.substring(10, 12);
if (len === 15) {
year = '19' + id.substring(6, 8);
month = id.substring(8, 10);
day = id.substring(10, 12);
} else {
year = value.substring(6, 10);
month = value.substring(10, 12);
day = value.substring(12, 14);
year = id.substring(6, 10);
month = id.substring(10, 12);
day = id.substring(12, 14);
}
const date = new Date(year, month - 1, day);
if (
date.getFullYear() !== parseInt(year, 10) ||
date.getMonth() + 1 !== parseInt(month, 10) ||
date.getDate() !== parseInt(day, 10)
) {
const y = parseInt(year, 10);
const m = parseInt(month, 10);
const d = parseInt(day, 10);
const now = new Date();
if (y < 1900 || y > now.getFullYear() || m < 1 || m > 12 || d < 1 || d > 31) {
return false;
}
const currentYear = new Date().getFullYear();
const birthYear = parseInt(year, 10);
if (birthYear < 1900 || birthYear > currentYear) {
const date = new Date(y, m - 1, d);
if (date.getFullYear() !== y || date.getMonth() + 1 !== m || date.getDate() !== d) {
return false;
}
// 18
if (len === 18) {
const Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
const Vi = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
let sum = 0;
for (let i = 0; i < 17; i++) {
sum += parseInt(id[i], 10) * Wi[i];
}
const checkCode = Vi[sum % 11];
if (checkCode !== id[17]) {
return false;
}
}
return true;
}
/**
@ -633,6 +636,7 @@ function handleOk() {
// params.stationId=storage.local.getItem('stationId')
//
if (params.identityType === '1' && !isValidIdCard(params.identityNo)) {
hideLoading()
return message.error('请输入正确的身份证号码')
}
let result = null

View File

@ -106,6 +106,9 @@
<template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template>
<template v-if="column.key === 'categoryId'">
<span>{{categoryList.find(item=>item.id==record.categoryId).name}}</span>
</template>
</template>
</a-table>
</a-modal>
@ -117,7 +120,7 @@
<script setup>
import { cloneDeep } from 'lodash-es'
import { ref, computed } from 'vue'
import { ref, computed,nextTick } from 'vue'
import { config } from '@/config'
import apis from '@/apis'
import { useForm, useModal, usePagination } from '@/hooks'
@ -142,6 +145,7 @@ const mapVisible = ref(false)
const stationList = ref([])
const spining = ref(false)
const areaCascaderRef=ref()
const categoryList = ref([])
formRules.value = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
identityType: [{ required: true, message: '请选择证件类型', trigger: 'change' }],
@ -169,7 +173,7 @@ 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: 'categoryId', key: 'categoryId', 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', },
@ -190,6 +194,7 @@ const rowSelection = computed(() => ({
}),
}))
getSeveicePeople()
getCategoriesAll()
async function getSeveicePeople() {
try {
const { success, data, total } = await apis.serviceStaffList
@ -208,6 +213,21 @@ async function getSeveicePeople() {
}
}
async function getCategoriesAll() {
try {
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) {
}
}
function onAreaChange(value, labels) {
formData.value.areaLabels = [...labels]
}
@ -260,6 +280,7 @@ const handleRemove = (item) => {
//
const handleConfirm = () => {
modalVisible.value = false
}
//
@ -299,6 +320,7 @@ async function handleEdit(record = {}, type) {
})
if (type == '2') {
formData.value.detailAddress = record.archive.homeDetailAddress
console.log(record.archive.homeDetailAddress)
gps.value = record.region.join('') + record.archive.homeDetailAddress
formData.value.lat = record.archive.lag
formData.value.lng = record.archive.lat
@ -307,6 +329,7 @@ async function handleEdit(record = {}, type) {
getServiceStation()
spining.value = false
} catch (error) {
console.log(error)
spining.value = false
}
@ -352,7 +375,8 @@ function handleOk() {
params.plannedServiceStartDate = formData.value.planeDate[0]
params.plannedEndDate = formData.value.planeDate[1]
}
params.projects = serviceList.value
params.projects =selectedServices.value
console.log(params)
let result = null
switch (modal.value.type) {
case 'create':
@ -389,6 +413,7 @@ function handleOk() {
*/
function handleCancel() {
selectedServices.value = []
formData.value={}
hideModal()
}

View File

@ -5,7 +5,7 @@
<a-row :gutter="24">
<a-col :span="8" v-if="platForm !== 'yunying'">
<a-form-item label="所在站点" name="stationId">
<ServiceStation v-model:value="searchFormData.stationId" />
<ServiceStation v-model:value="searchFormData.stationId" />
</a-form-item>
</a-col>
<!-- 所在区域 -->
@ -244,8 +244,9 @@
</template>
<template #extra>
<a-space>
<a-button type="primary" v-if="platForm!=='hujiao'" @click="$refs.editDialogRef.handleCreate()">新建</a-button>
<a-dropdown v-if="platForm!=='hujiao'">
<a-button type="primary" v-if="platForm !== 'hujiao'"
@click="$refs.editDialogRef.handleCreate()">新建</a-button>
<a-dropdown v-if="platForm !== 'hujiao'">
<template #overlay>
<a-menu @click="handleMenuClick">
<a-menu-item key="1">
@ -260,11 +261,11 @@
<UserOutlined />
联系人导入
</a-menu-item>
<a-menu-item key="4" v-if="platForm==='yunying'">
<a-menu-item key="4" v-if="platForm === 'yunying'">
<UserOutlined />
绑定服务人员
</a-menu-item>
<a-menu-item key="5" v-if="platForm==='yunying'">
<a-menu-item key="5" v-if="platForm === 'yunying'">
<UserOutlined />
绑定管家
</a-menu-item>
@ -279,9 +280,9 @@
<a-button>导入记录</a-button>
<a-button>导出</a-button>
<a-button>导出记录</a-button>
<a-button v-if="platForm==='yunying'">批量下载二维码</a-button>
<a-button v-if="platForm==='yunying'">二维码记录</a-button>
<a-button v-if="platForm==='yunying'">历史服务对象</a-button>
<a-button v-if="platForm === 'yunying'">批量下载二维码</a-button>
<a-button v-if="platForm === 'yunying'">二维码记录</a-button>
<a-button v-if="platForm === 'yunying'">历史服务对象</a-button>
</a-space>
</template>
<a-table :columns="columns" :data-source="listData" bordered="true" :loading="loading"
@ -305,7 +306,7 @@
<template v-if="column.key === 'serviceRecipientCategory'">
<span>{{
dicsStore.getDictLabel('Service_Recipient_Category2', record.serviceRecipientCategory)
}}</span>
}}</span>
</template>
<template v-if="column.key === 'disabilityType'">
@ -315,7 +316,7 @@
<template v-if="column.key === 'disabilityLevel'">
<span>{{ dicsStore.getDictLabel('Disability_Level', record.disabilityLevel) }}</span>
</template>
<template v-if="'action' === column.key">
@ -325,7 +326,7 @@
<x-action-button @click="$refs.detailRef.handleEdit(record)">
<span>详情</span>
</x-action-button>
<x-action-button v-if="platForm==='yunying'">
<!-- <x-action-button v-if="platForm==='yunying'">
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent>
绑定
@ -341,16 +342,16 @@
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</x-action-button>
</a-dropdown>
</x-action-button> -->
<x-action-button @click="$refs.lineOrderRef.handleEdit(record, '2')">
<span>线下工单</span>
</x-action-button>
<x-action-button @click="$refs.lineOrderRef.handleEdit(record, '1')"
<!-- <x-action-button @click="$refs.lineOrderRef.handleEdit(record, '1')"
v-if="platForm !== 'yunying'">
<span>线上工单</span>
</x-action-button>
<x-action-button @click="$refs.transferRef.handleCreate(record.id,record.stationId)">
</x-action-button> -->
<x-action-button @click="$refs.transferRef.handleCreate(record.id, record.stationId)">
<span>转出</span>
</x-action-button>
</template>
@ -360,7 +361,7 @@
</a-col>
</a-row>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
<detail ref="detailRef" ></detail>
<detail ref="detailRef"></detail>
<LineOrder2 ref="lineOrderRef" />
<TransferOut ref="transferRef" @ok="onOk" />
<!-- <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">
@ -384,7 +385,7 @@ import { useDicsStore } from '@/store'
import AreaCascader from '@/components/AreaCascader/index.vue'
import NodeTree from '@/components/NodeTree/index.vue'
import dayjs from 'dayjs'
import {DownOutlined} from '@ant-design/icons-vue'
import { DownOutlined } from '@ant-design/icons-vue'
import storage from '@/utils/storage'
import TransferOut from './components/TransferOut.vue'
import ServiceStation from '@/components/ServiceStation/index.vue'
@ -396,7 +397,7 @@ const totalCount = ref(0) // 总人数
const dicsStore = useDicsStore()
const lineOpen = ref(false)
const lineTitle = ref('线下工单')
const transferRef=ref()
const transferRef = ref()
const serviceName = ref('')
const columns = [
{
@ -475,20 +476,23 @@ const columns = [
// --- ---
{
title: '去世时间',
dataIndex: 'passWayAt',
key: 'passWayAt',
dataIndex: 'livingStatus.passWayAt',
key: 'livingStatus.passWayAt',
align: 'center',
width: 140,
customRender: ({ text, record }) => {
return text ? dayjs(text).format('YYYY-MM-DD') : '-';
return record.livingStatus.passWayAt ? dayjs(record.livingStatus.passWayAt).format('YYYY-MM-DD') : '-';
},
},
// --- ---
{
title: '去世原因',
dataIndex: 'passWayReason',
key: 'passWayReason',
dataIndex: 'livingStatus.passWayReason',
key: 'livingStatus.passWayReason',
align: 'center',
customRender: ({ text, record }) => {
return record.livingStatus.passWayReason;
},
width: 140,
},
// --- ---
@ -648,8 +652,8 @@ async function getPageList() {
const { pageSize, current } = paginationState
const { success, data, total } = await apis.serverObj
.getProjectList({
stationId:storage.local.getItem('stationId')||'',
companyId:storage.local.getItem('companyId'),
stationId: storage.local.getItem('stationId') || '',
companyId: storage.local.getItem('companyId'),
pageSize,
current: current,
...searchFormData.value,
@ -661,7 +665,7 @@ async function getPageList() {
if (config('http.code.success') === success) {
listData.value = data
paginationState.total = total
totalCount.value = total||0
totalCount.value = total || 0
}
} catch (error) {

View File

@ -249,28 +249,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()
}
},
})
}
/**
* 删除
*/
@ -283,7 +262,7 @@ function handleDelete({ id }) {
return new Promise((resolve, reject) => {
; (async () => {
try {
const { success } = await apis.productOrder.delItem(id).catch(() => {
const { success } = await apis.serviceStaffList.delItem(id).catch(() => {
throw new Error()
})
if (config('http.code.success') === success) {

View File

@ -297,7 +297,7 @@
<x-action-button @click="$refs.detailRef.handleCreate(record)">
<span>详情</span>
</x-action-button>
<x-action-button v-if="platForm==='yunying'">
<!-- <x-action-button v-if="platForm==='yunying'">
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent>
绑定
@ -314,7 +314,7 @@
</a-menu>
</template>
</a-dropdown>
</x-action-button>
</x-action-button> -->
<x-action-button @click="$refs.lineOrderRef.handleEdit(record, '2')">
<span>线下工单</span>
</x-action-button>

638
yarn.lock

File diff suppressed because it is too large Load Diff