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 VITE_ROUTER_HISTORY=hash
# api # 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_UPLOAD='http://115.239.217.220:9458'
VITE_API_HTTP=/api/v1/ VITE_API_HTTP=/api/v1/
# storage # storage

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

View File

@ -41,6 +41,7 @@ const theme = ref({
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: transparent; background-color: transparent;
padding: 20px; padding: 20px;
color: #ffffff;
} }
.bottom-center .amap-info-sharp:after { .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 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 --> <!-- AreaCascader.vue -->
<template> <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" :style="style" :disabled="disabled" :show-search="showSearch" :allow-clear="allowClear"
:change-on-select="changeOnSelect" :field-names="fieldNames" @change="handleChange" ref="cascaderRef" /> :change-on-select="changeOnSelect" :field-names="fieldNames" @change="handleChange" ref="cascaderRef" />
</template> </template>
<script setup> <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 apis from '@/apis';
import { useDicsStore } from '@/store'; import { useDicsStore } from '@/store';
const dicsStore = useDicsStore(); const dicsStore = useDicsStore();
const modelValue = defineModel();
// 🔸 使 defineProps v-model props
const props = defineProps({ const props = defineProps({
modelValue: {
type: String,
default: ''
},
placeholder: { type: String, default: '请选择省市区' }, placeholder: { type: String, default: '请选择省市区' },
style: { type: Object, default: () => ({ width: '100%' }) }, style: { type: Object, default: () => ({ width: '100%' }) },
disabled: { type: Boolean, default: false }, disabled: { type: Boolean, default: false },
@ -23,26 +28,50 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({ default: () => ({
label: 'label', label: 'label',
value: 'code', value: 'code'
// children: 'children' // children
}) })
} }
}); });
const emit = defineEmits(['change']); // 🔸 emit v-model change
const options = ref([]); const emit = defineEmits(['update:modelValue', 'change']);
// 🔁 store // 🔸 a-cascader v-model:value
const innerValue = ref([]);
// 🔁 modelValue
watch( watch(
() => dicsStore.provinceOptions, () => props.modelValue,
(newVal) => { (newVal) => {
if (newVal && newVal.length > 0) { if (newVal && typeof newVal === 'string') {
options.value = newVal; 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 } { 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) { function findNodeInOptions(options, code) {
@ -55,37 +84,14 @@ function findNodeInOptions(options, code) {
} }
return null; 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 loadData = async (selectedOptions) => {
const targetOption = selectedOptions[selectedOptions.length - 1]; const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true; targetOption.loading = true;
try { try {
const parentId = targetOption.id || targetOption.code; // id code const parentId = targetOption.id || targetOption.code;
const response = await apis.common.getAreaList({ const response = await apis.common.getAreaList({
current: 1, current: 1,
pageSize: 100, pageSize: 100,
@ -98,16 +104,15 @@ const loadData = async (selectedOptions) => {
const children = response.data.map(item => ({ const children = response.data.map(item => ({
...item, ...item,
isLeaf: !item.hasChild, isLeaf: !item.hasChild,
label: item.label || item.name, // label: item.label || item.name,
value: item.code value: item.code
})); }));
targetOption.children = children; targetOption.children = children;
} else { } else {
targetOption.children = []; targetOption.children = [];
} }
// //
options.value = [...options.value]; options.value = [...options.value];
} catch (error) { } catch (error) {
console.error('加载子节点失败:', error); console.error('加载子节点失败:', error);
@ -118,8 +123,38 @@ const loadData = async (selectedOptions) => {
// 📣 // 📣
const handleChange = (value, 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) || []); 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> </script>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -86,8 +86,7 @@
<span v-else></span> <span v-else></span>
</template> </template>
<template v-if="column.key === 'status'"> <template v-if="column.key === 'status'">
<a-tag v-if="record.status == '1'" color="green">启用</a-tag> <a-tag>{{ dicsStore.getDictLabel('STAFF_STATUS', record.status) }}</a-tag>
<a-tag v-else color="red">禁用</a-tag>
</template> </template>
<template v-if="column.key === 'serviceType'"> <template v-if="column.key === 'serviceType'">
<span>{{ dicsStore.getDictLabel('STAFF_TYPE', record.serviceType) }}</span> <span>{{ dicsStore.getDictLabel('STAFF_TYPE', record.serviceType) }}</span>
@ -100,11 +99,13 @@
<x-action-button @click="$refs.detailRef.handleEdit(record)"> <x-action-button @click="$refs.detailRef.handleEdit(record)">
<span>详情</span> <span>详情</span>
</x-action-button> </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> <span>服务项目</span>
</x-action-button> </x-action-button>
<x-action-button @click="$refs.editDialogRef.handleEdit(record)" v-if="platForm==='yunying'"> <x-action-button @click="handleStop(record)"
<span>停用</span> 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>
<x-action-button @click="handleDelete(record)"> <x-action-button @click="handleDelete(record)">
<span style="color: #ff4d4f;">删除</span> <span style="color: #ff4d4f;">删除</span>
@ -117,6 +118,19 @@
</a-row> </a-row>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog> <edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
<detail ref="detailRef"></detail> <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> </template>
<script setup> <script setup>
@ -133,9 +147,17 @@ import detail from './components/detail.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import NodeTree from '@/components/NodeTree/index.vue' import NodeTree from '@/components/NodeTree/index.vue'
import storage from '@/utils/storage' import storage from '@/utils/storage'
import { getBirthDate, spliceUrl } from '@/utils/util'
defineOptions({ defineOptions({
name: 'allocation', 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 dicsStore = useDicsStore()
const platForm = storage.local.getItem('platform') const platForm = storage.local.getItem('platform')
const columns = [ const columns = [
@ -228,6 +250,7 @@ getPageList()
async function getPageList() { async function getPageList() {
try { try {
loading.value = true
const { pageSize, current } = paginationState const { pageSize, current } = paginationState
const { success, data, total } = await apis.serviceStaffList const { success, data, total } = await apis.serviceStaffList
.getProjectList({ .getProjectList({
@ -244,32 +267,126 @@ async function getPageList() {
if (config('http.code.success') === success) { if (config('http.code.success') === success) {
listData.value = data listData.value = data
paginationState.total = total paginationState.total = total
loading.value = false
getServerProject()
} }
} catch (error) { } 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 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 () => {
const checkHandler = (record) => { try {
Modal.confirm({ const params = { servicePersonId: currentId.value, projectIds: checkedKeys.value }
title: '即将核销是否继续', const {success} = await apis.serviceStaffList.createProject(params)
content: t('button.confirm'), if(success){
okText: t('button.confirm'), message.success('绑定成功')
onOk: async () => { treeOpen.value=false
const params = { checkedKeys.value=[]
}
} catch (error) {
console.log(error)
}
}
const handleStop = async (record) => {
let params = {
...record, ...record,
status: 'success' birthDay: record.birthDate2
} }
const { success } = await apis.productOrder.updateItem(params.id, params).catch(() => {
// throw new Error() if (record.laborContract && record.laborContract.length > 0) {
}) params.laborContractStartAt = record.laborContract[0]
if (config('http.code.success') === success) { params.laborContractEndAt = record.laborContract[1]
// resolve()
message.success('核销成功')
await getPageList()
} }
}, 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

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

View File

@ -14,7 +14,7 @@
<a-col :span="6"> <a-col :span="6">
<a-form-item label="项目分类" name="categoryId"> <a-form-item label="项目分类" name="categoryId">
<a-select v-model:value="searchFormData.categoryId" allowClear> <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> item.name }}</a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
@ -50,7 +50,9 @@
<template v-if="column.key === 'categoryType'"> <template v-if="column.key === 'categoryType'">
<span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span> <span>{{ dicsStore.getDictLabel('PROJECT_TYPE', record.categoryType) }}</span>
</template> </template>
<template v-if="column.key === 'categoryId'">
<span>{{categoryList.find(item=>item.id==record.categoryId).name}}</span>
</template>
<template v-if="column.key === 'price'"> <template v-if="column.key === 'price'">
<span>{{ record.price + record.frequencyUnit }}</span> <span>{{ record.price + record.frequencyUnit }}</span>
</template> </template>
@ -86,7 +88,7 @@ const categoryList=ref([])
const columns = [ const columns = [
{ title: '序号', dataIndex: 'serialNumber', key: 'serialNumber', align: 'center', width: 80, }, { title: '序号', dataIndex: 'serialNumber', key: 'serialNumber', align: 'center', width: 80, },
{ title: '类型', dataIndex: 'categoryType', key: 'categoryType', align: 'center', width: 100, }, { 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: 'name', key: 'name', align: 'center', },
{ title: '价格', dataIndex: 'price', key: 'price', align: 'center', }, { title: '价格', dataIndex: 'price', key: 'price', align: 'center', },
{ title: '简介', dataIndex: 'content', key: 'content', align: 'center', }, { title: '简介', dataIndex: 'content', key: 'content', align: 'center', },

View File

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

View File

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

View File

@ -244,7 +244,8 @@
</template> </template>
<template #extra> <template #extra>
<a-space> <a-space>
<a-button type="primary" v-if="platForm!=='hujiao'" @click="$refs.editDialogRef.handleCreate()">新建</a-button> <a-button type="primary" v-if="platForm !== 'hujiao'"
@click="$refs.editDialogRef.handleCreate()">新建</a-button>
<a-dropdown v-if="platForm !== 'hujiao'"> <a-dropdown v-if="platForm !== 'hujiao'">
<template #overlay> <template #overlay>
<a-menu @click="handleMenuClick"> <a-menu @click="handleMenuClick">
@ -325,7 +326,7 @@
<x-action-button @click="$refs.detailRef.handleEdit(record)"> <x-action-button @click="$refs.detailRef.handleEdit(record)">
<span>详情</span> <span>详情</span>
</x-action-button> </x-action-button>
<x-action-button v-if="platForm==='yunying'"> <!-- <x-action-button v-if="platForm==='yunying'">
<a-dropdown> <a-dropdown>
<a class="ant-dropdown-link" @click.prevent> <a class="ant-dropdown-link" @click.prevent>
绑定 绑定
@ -342,14 +343,14 @@
</a-menu> </a-menu>
</template> </template>
</a-dropdown> </a-dropdown>
</x-action-button> </x-action-button> -->
<x-action-button @click="$refs.lineOrderRef.handleEdit(record, '2')"> <x-action-button @click="$refs.lineOrderRef.handleEdit(record, '2')">
<span>线下工单</span> <span>线下工单</span>
</x-action-button> </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'"> v-if="platForm !== 'yunying'">
<span>线上工单</span> <span>线上工单</span>
</x-action-button> </x-action-button> -->
<x-action-button @click="$refs.transferRef.handleCreate(record.id, record.stationId)"> <x-action-button @click="$refs.transferRef.handleCreate(record.id, record.stationId)">
<span>转出</span> <span>转出</span>
</x-action-button> </x-action-button>
@ -475,20 +476,23 @@ const columns = [
// --- --- // --- ---
{ {
title: '去世时间', title: '去世时间',
dataIndex: 'passWayAt', dataIndex: 'livingStatus.passWayAt',
key: 'passWayAt', key: 'livingStatus.passWayAt',
align: 'center', align: 'center',
width: 140, width: 140,
customRender: ({ text, record }) => { customRender: ({ text, record }) => {
return text ? dayjs(text).format('YYYY-MM-DD') : '-'; return record.livingStatus.passWayAt ? dayjs(record.livingStatus.passWayAt).format('YYYY-MM-DD') : '-';
}, },
}, },
// --- --- // --- ---
{ {
title: '去世原因', title: '去世原因',
dataIndex: 'passWayReason', dataIndex: 'livingStatus.passWayReason',
key: 'passWayReason', key: 'livingStatus.passWayReason',
align: 'center', align: 'center',
customRender: ({ text, record }) => {
return record.livingStatus.passWayReason;
},
width: 140, width: 140,
}, },
// --- --- // --- ---

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) => { return new Promise((resolve, reject) => {
; (async () => { ; (async () => {
try { try {
const { success } = await apis.productOrder.delItem(id).catch(() => { const { success } = await apis.serviceStaffList.delItem(id).catch(() => {
throw new Error() throw new Error()
}) })
if (config('http.code.success') === success) { if (config('http.code.success') === success) {

View File

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

638
yarn.lock

File diff suppressed because it is too large Load Diff