长者标签

This commit is contained in:
1378012178@qq.com 2025-08-15 08:56:00 +08:00
parent 6b6d4c06d3
commit a0a069be47
19 changed files with 3157 additions and 0 deletions

View File

@ -0,0 +1,107 @@
<template>
<a-card :class="{
'selected-card': isSelected,
'directive-selected-card': isDirectiveSelected,
'org-card': clickable
}"
style="width: 100%; border-radius: 8px;"
:style="{ cursor: clickable ? 'pointer' : 'default' }"
:bodyStyle="{ padding: '24px' }"
@click="handleClick">
<div>
<a-row style="font-weight: normal; margin-bottom: 12px;">
<a-col :span="layout === 'full' ? 16 : 13" style="font-size: 14px;">
<div>
<span style="font-weight: bold;">{{ orgInfo.departName }}</span>
</div>
</a-col>
<a-col :span="layout === 'full' ? 8 : 11" style="text-align: right;">
<div style="display: flex; align-items: center; justify-content: flex-end; gap: 8px;">
<span v-if="isDirectiveMain" style="color: green; font-size: 12px; font-weight: bold; white-space: nowrap;">
标准指令库
</span>
<div class="zxClass" style="min-width: 35px;">{{ orgInfo.orgCode }}</div>
</div>
</a-col>
</a-row>
<a-divider />
<div style="position: relative;">
<div v-show="showDetail" style="text-align:center;position: absolute;top: 0px;right:0px">
<a-button type="link" size="small" @click.stop="handleDetail">详情</a-button>
</div>
<div>
<p>加盟时间{{ orgInfo.franchiseTime?.substring(0, 10) }}</p>
<p>机构负责人{{ orgInfo.orgLeader }}</p>
<p>负责人电话{{ orgInfo.orgLeaderPhone }}</p>
<p class="ellipsis-one-lines" :title="orgInfo.comRegisterAddress">机构地址{{ orgInfo.comRegisterAddress }}</p>
</div>
</div>
</div>
</a-card>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
const props = defineProps({
orgInfo: { type: Object, required: true },
layout: { type: String, default: 'full' },
isSelected: { type: Boolean, default: false },
isDirectiveSelected: { type: Boolean, default: false },
isDirectiveMain: { type: Boolean, default: false },
showDetail: { type: Boolean, default: false },
clickable: { type: Boolean, default: false }
})
const emit = defineEmits(['click', 'detail'])
const handleClick = () => {
emit('click', props.orgInfo)
}
const handleDetail = () => {
emit('detail', props.orgInfo)
}
</script>
<style lang="less" scoped>
.zxClass {
font-size: 12px;
background: linear-gradient(to right, #1ea0fa, #017de9);
border-radius: 8px;
height: 25px;
color: white;
line-height: 25px;
padding: 0 8px;
flex-shrink: 0;
}
.ellipsis-one-lines {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.selected-card {
border: 2px solid #1890ff;
box-shadow: 0 0 8px rgba(24, 144, 255, 0.3);
}
.directive-selected-card {
border: 2px solid #1890FF;
box-shadow: 0 0 8px rgba(37, 149, 255, 0.3);
}
.org-card {
&:hover {
border-color: #55a9f8;
box-shadow: 0 2px 8px rgba(37, 149, 255, 0.3);
}
}
:deep .ant-divider {
margin: 0 0 8px 0;
}
</style>

View File

@ -0,0 +1,153 @@
<template>
<a-card :class="{
'selected-card': isSelected,
'directive-selected-card': isDirectiveSelected,
'org-card': clickable
}" style="width: 100%; border-radius: 8px;" :style="{ cursor: clickable ? 'pointer' : 'default' }"
:bodyStyle="{ padding: '24px' }" @click="handleClick">
<div>
<a-row style="font-weight: normal; margin-bottom: 12px;">
<a-col :span="existTagFunc() ? 16 : 21">
<div>
<span class="ellipsis-one-lines1" :title="orgInfo.departName" style="font-size: 17px; font-weight: bold;">{{
orgInfo.departName
}}</span>
</div>
</a-col>
<a-col :span="existTagFunc() ? 8 : 3" style="text-align: right;">
<div style="display: flex; align-items: center; justify-content: flex-end; gap: 8px;">
<span v-if="isDirectiveMain"
style="color: #909399; font-size: 12px; font-weight: bold; white-space: nowrap;">
标准指令库
</span>
<span v-if="isElderTagMain"
style="color: #909399; font-size: 12px; font-weight: bold; white-space: nowrap;">
标准标签库
</span>
<div class="zxClass" :class="{ 'zxbkClass': existTagFunc() }" style="min-width: 35px;">{{ orgInfo.orgCode
}}
</div>
</div>
</a-col>
</a-row>
<div style="position: relative;">
<div>
<div><span style="color: #909399;">机构负责人</span>{{ orgInfo.orgLeader }}</div>
<div><span style="color: #909399;">负责人电话</span>{{ orgInfo.orgLeaderPhone }}</div>
</div>
<div class="org-address">
<span class="ellipsis-one-lines2" :title="orgInfo.comRegisterAddress">{{ orgInfo.comRegisterAddress }}</span>
</div>
<div
style="font-size: 12px; display: flex; justify-content: space-between; align-items: center; margin-top: 12px;">
<span style="color: #909399;">加盟时间{{ orgInfo.franchiseTime?.substring(0, 10) }}</span>
<a-button style="font-size: 12px;" v-show="showDetail" type="link" size="small"
@click.stop="handleDetail">了解更多</a-button>
</div>
</div>
</div>
</a-card>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue'
const props = defineProps({
orgInfo: { type: Object, required: true },
layout: { type: String, default: 'full' },
isSelected: { type: Boolean, default: false },
isDirectiveSelected: { type: Boolean, default: false },
isDirectiveMain: { type: Boolean, default: false },//
isElderTagMain: { type: Boolean, default: false },//
showDetail: { type: Boolean, default: false },
clickable: { type: Boolean, default: false }
})
const emit = defineEmits(['click', 'detail'])
const existTagFunc = () => {
return props.isDirectiveMain || props.isElderTagMain
}
const handleClick = () => {
emit('click', props.orgInfo)
}
const handleDetail = () => {
emit('detail', props.orgInfo)
}
</script>
<style lang="less" scoped>
.zxClass {
font-size: 12px;
background-color: white;
border: 1px solid #e4e4e4;
border-radius: 8px;
height: 25px;
color: #7c7c7c;
line-height: 25px;
padding: 0 8px;
flex-shrink: 0;
}
.zxbkClass {
background-color: #F5F7FF;
}
.selected-card {
border: 2px solid #1890ff;
box-shadow: 0 0 8px rgba(24, 144, 255, 0.3);
}
.directive-selected-card {
border: 2px solid #1890FF;
box-shadow: 0 0 8px rgba(37, 149, 255, 0.3);
}
.org-card {
&:hover {
border-color: #55a9f8;
box-shadow: 0 2px 8px rgba(37, 149, 255, 0.3);
}
}
:deep .ant-divider {
margin: 0 0 8px 0;
}
.org-address {
width: 100%;
height: 65px;
background-color: #f8fbff;
background-image: url('./orgaddressbk.png');
background-repeat: no-repeat;
background-position: center;
background-size: cover;
padding: 13px;
padding-right: 100px;
color: #696c7f;
display: flex;
align-items: center;
margin-top: 10px;
border-radius: 10px;
font-size: 12.5px;
}
.ellipsis-one-lines1 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-overflow: ellipsis;
}
.ellipsis-one-lines2 {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.8;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,15 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/eldertag/canAddElderTag/list',
}
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });

View File

@ -0,0 +1,31 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { rules } from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '所属机构',
align: 'center',
dataIndex: 'sysOrgCode_dictText',
},
{
title: '标签类型',
align: 'center',
dataIndex: 'type_dictText',
},
{
title: '标签名称',
align: 'center',
dataIndex: 'tagName',
},
{
title: '价格(元)',
align: 'center',
dataIndex: 'price',
},
];
// 高级查询数据
export const superQuerySchema = {};

View File

@ -0,0 +1,234 @@
<template>
<div class="p-2">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :lg="6">
<a-form-item name="sysOrgCode">
<template #label><span title="所属机构">所属机构</span></template>
<j-dict-select-tag placeholder="请选择所属机构" v-model:value="queryParam.sysOrgCode"
dictCode="sys_depart,depart_name,org_code" allow-clear />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="type">
<template #label><span title="标签类型">标签类型</span></template>
<j-dict-select-tag v-model:value="queryParam.type" dictCode="elder_tag_type" placeholder="请选择标签类型"
allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="tagName">
<template #label><span title="标签名称">标签名称</span></template>
<JInput v-model:value="queryParam.tagName" placeholder="请输入标签名称" allowClear />
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset"
style="margin-left: 8px">重置</a-button>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<CanAddElderTagModal ref="registerModal" @success="handleSuccess"></CanAddElderTagModal>
</div>
</template>
<script lang="ts" name="canadddirective-canAddElderTag" setup>
import { ref, reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, superQuerySchema } from './CanAddElderTag.data';
import { list } from './CanAddElderTag.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import CanAddElderTagModal from './components/CanAddElderTagModal.vue'
import { useUserStore } from '/@/store/modules/user';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
import { useMessage } from '/@/hooks/web/useMessage';
const props = defineProps({
elderTagMainOrgInfo: {},
existETIds: [],
})
const { createMessage, createConfirm } = useMessage();
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
const userStore = useUserStore();
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '可新增长者标签',
api: list,
columns,
canResize: false,
useSearchForm: false,
actionColumn: {
width: 120,
fixed: 'right',
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: 24,
sm: 4,
xl: 6,
xxl: 5
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
xl: 18,
xxl: 19
});
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 镜像
*/
function handlePull(record) {
createConfirm({
iconType: 'warning',
title: '镜像确认',
content: '请确认是否将' + record.sysOrgCode_dictText + '新增的长者标签“' + record.type_dictText + ' - ' + record.tagName + '”镜像给当前标准标签库:' + props.elderTagMainOrgInfo.departName,
okText: '确认',
cancelText: '取消',
onOk: () => {
// syncDirective(
// record.orgCode,
// {
// syncIds: record.directiveId,
// upIds: '',
// syncOrgCodes: props.elderTagMainOrgInfo.orgCode,
// syncOption: 'all',
// }
// ).then(res => {
// createMessage.success(',!')
// emit('refreshExistIds', props.elderTagMainOrgInfo)
// }).catch(() => {
// createMessage.error('')
// })
}
});
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
// {
// label: '',
// onClick: handleDetail.bind(null, record),
// },
{
label: '镜像',
onClick: handlePull.bind(null, record),
}
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust {
min-width: 100px !important;
}
.query-group-split-cust {
width: 30px;
display: inline-block;
text-align: center
}
.ant-form-item:not(.ant-form-item-with-help) {
margin-bottom: 16px;
height: 32px;
}
:deep(.ant-picker),
:deep(.ant-input-number) {
width: 100%;
}
}
</style>

View File

@ -0,0 +1,120 @@
<template>
<a-spin :spinning="confirmLoading">
<JFormContainer :disabled="disabled">
<template #detail>
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol"
name="CanAddElderTagForm">
<a-row>
<a-col :span="24">
<a-form-item label="标签类型" v-bind="validateInfos.type" id="ElderTagForm-type" name="type">
<j-dict-select-tag v-model:value="formData.type" dictCode="elder_tag_type" placeholder="请选择标签类型"
allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="标签名称" v-bind="validateInfos.tagName" id="ElderTagForm-tagName" name="tagName">
<a-input v-model:value="formData.tagName" placeholder="请输入标签名称" allow-clear></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="价格(元)" v-bind="validateInfos.price" id="ElderTagForm-price" name="price">
<a-input-number v-model:value="formData.price" placeholder="请输入价格" style="width: 100%" :min="0"
:max="99.99" :precision="2" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="图标" v-bind="validateInfos.pic" id="ElderTagForm-pic" name="pic">
<JImageUpload :fileMax="1" v-model:value="formData.pic"></JImageUpload>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
</JFormContainer>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { Form } from 'ant-design-vue';
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({}) },
formBpm: { type: Boolean, default: true }
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
type: '',
tagName: '',
price: undefined,
createTime: '',
sysOrgCode: '',
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = reactive({
});
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
//
const disabled = computed(() => {
if (props.formBpm === true) {
if (props.formData.disabled === false) {
return false;
} else {
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
function add() {
edit({});
}
/**
* 编辑
*/
function edit(record) {
nextTick(() => {
resetFields();
const tmpData = {};
Object.keys(formData).forEach((key) => {
if (record.hasOwnProperty(key)) {
tmpData[key] = record[key]
}
})
//
Object.assign(formData, tmpData);
});
}
defineExpose({
add,
edit,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
padding: 14px;
}
</style>

View File

@ -0,0 +1,81 @@
<template>
<a-drawer :title="title" width="50vw" v-model:visible="visible" :closable="true"
:footer-style="{ textAlign: 'right' }" @cancel="handleCancel">
<template #footer>
<a-button @click="handleCancel" style="margin-right: 8px;">关闭</a-button>
</template>
<CanAddElderTagForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></CanAddElderTagForm>
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import CanAddElderTagForm from './CanAddElderTagForm.vue'
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
const title = ref<string>('');
const width = ref<number>(800);
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
/**
* 新增
*/
function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '编辑';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
defineExpose({
add,
edit,
disableSubmit,
});
</script>
<style lang="less">
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>
<style lang="less" scoped></style>

View File

@ -0,0 +1,97 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/elder/elderTag/list',
save='/elder/elderTag/add',
edit='/elder/elderTag/edit',
deleteOne = '/elder/elderTag/delete',
deleteBatch = '/elder/elderTag/deleteBatch',
importExcel = '/elder/elderTag/importExcel',
exportXls = '/elder/elderTag/exportXls',
listByDS = '/elder/elderTag/listByDS',
idListByDS = '/elder/elderTag/idListByDS',
syncElderTag = '/elder/elderTag/syncElderTag',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
*
* @param params
* @param handleSuccess
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
* @param handleSuccess
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
* @param isUpdate
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params }, { isTransformResponse: false });
}
/**
* -
* @param params
*/
export const listByDS = (params) => defHttp.get({ url: Api.listByDS, params });
/**
*
* @param params id
* @returns
*/
export const idListByDS = (params) => defHttp.get({ url: Api.idListByDS, params });
/**
*
* @param params
* @returns
*/
export const syncElderTag = (dataSourceCode: string, params: any) => {
return defHttp.post({ url: `${Api.syncElderTag}?sourceOrgCode=${encodeURIComponent(dataSourceCode)}`, params });
};

View File

@ -0,0 +1,77 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { rules } from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '标签类型',
align: 'center',
dataIndex: 'type_dictText',
},
{
title: '标签名称',
align: 'center',
dataIndex: 'tagName',
},
{
title: '价格(元)',
align: 'center',
dataIndex: 'price',
},
{
title: '图标',
align: 'center',
dataIndex: 'pic',
customRender: render.renderImage,
},
{
title: '排序',
align: 'center',
dataIndex: 'sort',
},
{
title: '是否启用',
align: 'center',
dataIndex: 'izEnabled_dictText',
},
];
export const columnsNoMedia: BasicColumn[] = [
{
title: '标签类型',
align: 'center',
dataIndex: 'type_dictText',
},
{
title: '标签名称',
align: 'center',
dataIndex: 'tagName',
},
{
title: '价格(元)',
align: 'center',
dataIndex: 'price',
},
{
title: '排序',
align: 'center',
dataIndex: 'sort',
},
{
title: '是否启用',
align: 'center',
dataIndex: 'izEnabled_dictText',
},
];
// 高级查询数据
export const superQuerySchema = {
type: { title: '标签类型', order: 0, view: 'text', type: 'string' },
tagName: { title: '标签名称', order: 1, view: 'text', type: 'string' },
price: { title: '价格', order: 2, view: 'number', type: 'number' },
pic: { title: '图标', order: 3, view: 'text', type: 'string' },
sort: { title: '排序', order: 4, view: 'number', type: 'number' },
izEnabled: { title: '是否启用', order: 5, view: 'text', type: 'string' },
};

View File

@ -0,0 +1,249 @@
<template>
<div class="p-2">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :lg="6">
<a-form-item name="type">
<template #label><span title="标签类型">标签类型</span></template>
<j-dict-select-tag v-model:value="queryParam.type" dictCode="elder_tag_type" placeholder="请选择标签类型"
allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="tagName">
<template #label><span title="标签名称">标签名称</span></template>
<JInput v-model:value="queryParam.tagName" placeholder="请输入标签名称" allowClear />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="izEnabled">
<template #label><span title="是否启用">是否启用</span></template>
<j-dict-select-tag type='list' placeholder="请选择是否启用" v-model:value="queryParam.izEnabled"
dictCode="iz_enabled" allow-clear />
</a-form-item>
</a-col>
<a-col :xl="6" :lg="7" :md="8" :sm="24">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset"
style="margin-left: 8px">重置</a-button>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable">
<!--插槽:table标题-->
<template #tableTitle>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<ElderTagModal ref="registerModal" @success="handleSuccess"></ElderTagModal>
</div>
</template>
<script lang="ts" name="eldertag-elderTag" setup>
import { ref, reactive, onMounted } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, superQuerySchema } from './ElderTag.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './ElderTag.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import ElderTagModal from './components/ElderTagModal.vue'
import { useUserStore } from '/@/store/modules/user';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
import { useMessage } from '/@/hooks/web/useMessage';
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
const userStore = useUserStore();
const isShowDM = ref(false)//
const mainOrgCode = ref()//
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '长者标签',
api: list,
columns,
canResize: false,
useSearchForm: false,
actionColumn: {
width: 120,
fixed: 'right',
},
defSort: {
column: 'sort',
order: 'asc',
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "长者标签",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: 24,
sm: 4,
xl: 6,
xxl: 4
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
});
//
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
searchQuery();
}
/**
* 新增事件
*/
function handleAdd() {
registerModal.value.disableSubmit = false;
registerModal.value.add();
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
registerModal.value.disableSubmit = false;
registerModal.value.edit(record);
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
registerModal.value.disableSubmit = true;
registerModal.value.edit(record);
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({ id: record.id }, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}
];
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
/**
* 查看指令库
*/
function handleDirectiveMainOpen() {
registerModal.value?.openDM(mainOrgCode.value)
}
//
onMounted(() => {
});
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust {
min-width: 100px !important;
}
.query-group-split-cust {
width: 30px;
display: inline-block;
text-align: center
}
.ant-form-item:not(.ant-form-item-with-help) {
margin-bottom: 16px;
height: 32px;
}
:deep(.ant-picker),
:deep(.ant-input-number) {
width: 100%;
}
}
</style>

View File

@ -0,0 +1,567 @@
<template>
<div class="p-2" style="overflow-x: hidden;">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :lg="5">
<a-form-item name="instructionTagId">
<template #label><span title="分类标签">分类标签</span></template>
<j-dict-select-tag v-model:value="queryParam.instructionTagId" :disabled="!showJSCom"
:orgCode="sourceOrgInfo?.orgCode"
:dictCode="`nu_config_service_instruction_tag,instruction_name,id,del_flag = 0 and iz_enabled = 0 order by sort asc`"
placeholder="请选择分类标签" allowClear :ignoreDisabled="true" @select="reload()" />
<!-- <span v-else>请选择源平台</span> -->
</a-form-item>
</a-col>
<a-col :lg="5">
<a-form-item name="categoryId">
<template #label><span title="服务类别">服务类别</span></template>
<j-dict-select-tag type="list" v-model:value="queryParam.categoryId" :disabled="!showJSCom"
:orgCode="sourceOrgInfo?.orgCode"
:dictCode="`nu_config_service_category,category_name,id,del_flag = 0 and iz_enabled = 0 and instruction_id = '${queryParam.instructionTagId || ''}' order by sort asc`"
placeholder="请选择服务类别" allowClear :ignoreDisabled="true" @select="reload()" />
</a-form-item>
</a-col>
<a-col :lg="5">
<a-form-item name="typeId">
<template #label><span title="服务类型">服务类型</span></template>
<j-dict-select-tag type="list" v-model:value="queryParam.typeId" :disabled="!showJSCom"
:orgCode="sourceOrgInfo?.orgCode"
:dictCode="`nu_config_service_type,type_name,id,del_flag = 0 and iz_enabled = 0 and category_id = '${queryParam.categoryId || ''}' order by sort asc`"
placeholder="请选择服务类型" allowClear :ignoreDisabled="true" @select="reload()" />
</a-form-item>
</a-col>
<a-col :lg="5">
<a-form-item name="directiveName">
<template #label><span title="服务指令">服务指令</span></template>
<JInput v-model:value="queryParam.directiveName" placeholder="请输入服务指令名称" allowClear />
</a-form-item>
</a-col>
<!-- <a-col :lg="6">
<a-form-item name="bodyTags">
<template #label><span title="体型标签">体型标签</span></template>
<j-dict-select-tag type='list' v-model:value="queryParam.bodyTags"
:dictCode="`nu_config_body_tag,tag_name,id,del_flag = '0' and iz_enabled = 0 order by sort asc`" :ignoreDisabled="true"
placeholder="请选择体型标签" allowClear />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="emotionTags">
<template #label><span title="情绪标签">情绪标签</span></template>
<j-dict-select-tag type="list" v-model:value="queryParam.emotionTags"
:dictCode="`nu_config_emotion_tag,tag_name,id,del_flag = '0' and iz_enabled = 0 order by sort asc`" :ignoreDisabled="true"
placeholder="请选择情绪标签" allowClear />
</a-form-item>
</a-col> -->
<!-- <a-col :lg="6">
<a-form-item name="izEnabled">
<template #label><span title="是否启用">是否启用</span></template>
<j-dict-select-tag type='list' v-model:value="queryParam.izEnabled" dictCode="iz_enabled"
:ignoreDisabled="true" placeholder="请选择是否启用" allowClear @select="reload()" />
</a-form-item>
</a-col> -->
<a-col :xl="4" :lg="4" :md="4" :sm="4">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<!-- <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button> -->
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset"
style="margin-left: 8px">重置</a-button>
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<a-row :gutter="24" style="padding-left: 20px;padding-right: 20px;">
<a-col :lg="12" :sm="24">
<!-- 引用表格 -->
<a-tag color="blue" style="margin-left: 10px;margin-top: 10px;">源平台 - {{ sourceOrgInfo.departName }}</a-tag>
<a-divider type="vertical" style="background-color: #CDCDCF;margin-left:5px;margin-right:10px;" />
<a-radio-group v-model:value="sourceType" size="small" @change="sourceTypeChanged">
<a-radio-button value="all">全部</a-radio-button>
<a-radio-button value="unsel">可同步</a-radio-button>
</a-radio-group>
<a-divider type="vertical" style="background-color: #CDCDCF;margin-left:10px;margin-right:10px;" />
<a-button type="primary" @click="selectAll" size="small">一键全选</a-button>
<BasicTable @register="registerTable" :dataSource="leftList" size="small" :rowClassName="rowClassName"
:columns="targetChooseType == 'one' ? sourceColumns : targetSourceColumns" :scroll="{ y: '57vh' }">
<template #tableTitle></template>
<template v-slot:bodyCell="{ column, record, index, text }">
<!-- <template v-if="column.dataIndex === 'bodyTagList'">
<span :title="text.map((item) => item.tagName).join('、')">{{text.map((item) =>
item.tagName).join('、')}}</span>
</template>
<template v-if="column.dataIndex === 'emotionTagList'">
<span :title="text.map((item) => item.tagName).join('、')">{{text.map((item) =>
item.tagName).join('、')}}</span>
</template> -->
<template v-if="column.dataIndex === 'izExist'">
<a-tag v-if="rightSourceList.some(item => item.id === record.id)" color="orange">已存在</a-tag>
<a-tag v-else>可新增</a-tag>
<!-- <span v-if="rightSourceList.some(item => item.id === record.id)" style="color: #EFBD48;">已存在</span>
<span v-else>可新增</span> -->
</template>
</template>
<template #action="{ record }">
<a-button type="link" v-if="!selectedRecordIds.includes(record.id)" @click="selectRecord(record)"
size="small">选择</a-button>
<!-- :disabled="rightSourceList.some(item => item.id === record.id)" -->
<a-button type="link" v-else @click="removeRecord(record)" size="small">移除</a-button>
</template>
</BasicTable>
</a-col>
<a-col :lg="12" :sm="24">
<a-tag v-if="targetChooseType == 'one'" color="green" style="margin-left: 10px;margin-top: 10px;">
目标平台 - {{ targetOrgs[0]?.departName }} - 已选择 {{ rightNeedAddList.length }}
</a-tag>
<a-tag v-else color="green" style="margin-left: 10px;margin-top: 10px;">
已选择 {{ rightNeedAddList.length }}
</a-tag>
<a-divider v-if="targetChooseType == 'one'" type="vertical" style="background-color: #CDCDCF;margin-left:5px;margin-right:10px;" />
<a-radio-group v-if="targetChooseType == 'one'" v-model:value="targetType" size="small"
@change="targetTypeChanged">
<a-radio-button value="exist">已有</a-radio-button>
<a-radio-button value="needsync">待同步</a-radio-button>
</a-radio-group>
<a-divider type="vertical" style="background-color: #CDCDCF;margin-left:10px;margin-right:10px;" />
<a-button type="primary" @click="removeAll" size="small">全部移除</a-button>
<!-- <a-divider type="vertical" style="background-color: #CDCDCF" />
<a-button type="warning" @click="syncFunc" size="small">同步</a-button> -->
<BasicTable bordered
:dataSource="targetChooseType == 'one' ? (targetType == 'needsync' ? rightNeedAddList : rightSourceList) : rightNeedAddList"
:columns="targetChooseType == 'one' ? (targetType == 'needsync' ? targetColumns : targetSourceColumns) : targetSourceColumns"
size="small" :scroll="{ y: '57vh' }"
:pagination="{ current: 1, pageSize: 15, total: targetType == 'needsync' ? rightNeedAddList.length :rightSourceList.length, showSizeChanger: true, pageSizeOptions: ['15', '50', '70', '100'] }">
<template v-slot:bodyCell="{ column, record, index, text }">
<template v-if="column.dataIndex === 'izExist'">
<a-tag v-if="rightSourceList.some(item => item.id === record.id)" color="orange">更新</a-tag>
<a-tag v-else color="green">新增</a-tag>
<!-- <span v-if="rightSourceList.some(item => item.id === record.id)" style="color: #EFBD48;">待更新</span>
<span v-else>待新增</span> -->
</template>
</template>
</BasicTable>
</a-col>
</a-row>
</div>
<a-modal v-model:visible="visible" width="30vw" title="数据同步确认" :ok-text="'确认'" :cancel-text="'取消'" @ok="handleOk"
@cancel="handleCancel">
<!-- 指定机构同步 -->
<div style="padding: 20px;" v-if="targetChooseType == 'one'">
<p>目标机构 {{ targetOrg?.departName }}</p>
<p>新增服务指令 {{ getNewCount() }} </p>
<p>更新服务指令 {{ getUpdateCount() }} </p>
<!-- <span>请选择"新增指令"需要同步的内容</span>
<a-radio-group v-model:value="syncOption">
<a-radio value="all">全部</a-radio>
<a-radio value="business">业务字段</a-radio>
<a-radio value="media">指令资源</a-radio>
</a-radio-group> -->
</div>
<!-- 批量同步 -->
<div style="padding: 20px;" v-else>
<p>同步服务指令 {{ rightNeedAddList.length }} </p>
<!-- <span>请选择"服务指令"需要同步的内容</span>
<a-radio-group v-model:value="syncOption">
<a-radio value="all">全部</a-radio>
<a-radio value="business">业务字段</a-radio>
<a-radio value="media">指令资源</a-radio>
</a-radio-group> -->
</div>
</a-modal>
</template>
<script lang="ts" name="serviceDirective-configServiceDirective" setup>
import { ref, reactive, onMounted, watch } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, sourceColumns, superQuerySchema, targetSourceColumns, targetColumns } from './ConfigServiceDirective.data';
import { listByDS } from './ConfigServiceDirective.api';
import { useUserStore } from '/@/store/modules/user';
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import { cloneDeep } from "lodash-es";
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { useMessage } from '/@/hooks/web/useMessage';
import { syncDirective } from '/@/views/synchronization/directive/serviceDirective/ConfigServiceDirective.api';
const { createConfirm } = useMessage();
const props = defineProps({
targetOrgs: [],//
targetChooseType: '',
})
const leftList = ref<any[]>([]); //
const rightSourceList = ref<any[]>([]); //
const rightNeedAddList = ref<any[]>([]); //
const sourceOrgInfo = ref({})//
const sourceType = ref('all')//
const targetType = ref('needsync')//
const showJSCom = ref(false)
const selectedRecordIds = ref<string[]>([]); // ID
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
const userStore = useUserStore();
const targetOrg = ref()//
const { createMessage } = useMessage();
const visible = ref(false);
const syncOption = ref('all');
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: '服务指令',
api: listByDS,
canResize: false,
useSearchForm: false,
showIndexColumn: true,
showTableSetting: false,
immediate: false,
pagination: {
current: 1,
pageSize: 15,
pageSizeOptions: ['15', '50', '70', '100'],
},
beforeFetch: async (params) => {
queryParam.izEnabled = '0'
return Object.assign(params, queryParam);
},
actionColumn: {
width: 60,
fixed: 'right',
},
},
});
const [registerTable, { reload, collapseAll, updateTableDataRecord, findTableDataRecord, getDataSource }, { rowSelection, selectedRowKeys }] = tableContext;
const labelCol = reactive({
xs: 24,
sm: 6,
xl: 6,
xxl: 6
});
const wrapperCol = reactive({
xs: 24,
sm: 18,
});
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
function init(record) {
sourceOrgInfo.value = record.orgInfo
//
{
rightNeedAddList.value = []
leftList.value = []
selectedRecordIds.value = []
formRef.value.resetFields();
selectedRowKeys.value = [];
sourceType.value = 'all'
targetType.value = 'needsync'
}
queryParam.dataSourceCode = record.orgInfo.orgCode;
reload();
}
function resetTargetData() {
//
{
rightNeedAddList.value = []
selectedRecordIds.value = []
formRef.value.resetFields();
selectedRowKeys.value = [];
sourceType.value = 'all'
targetType.value = 'needsync'
}
}
function initTargetList(record) {
targetOrg.value = {}
// - +
if (!!record.orgCode) {
targetOrg.value = record
resetTargetData()
listByDS({
dataSourceCode: record.orgCode,
pageNo: 1,
pageSize: -1,
}).then(res => {
rightNeedAddList.value = []
selectedRecordIds.value = []
rightSourceList.value = res.records
// selectedRecordIds.value = rightSourceList.value?.map(d => d.id)
})
}
}
//
function selectRecord(record: any) {
if (!selectedRecordIds.value.includes(record.id)) {
selectedRecordIds.value.push(record.id); // ID
rightNeedAddList.value.push(record); //
leftList.value = leftList.value.filter(item => item.id !== record.id); //
rightNeedAddList.value = [...rightNeedAddList.value]; //
leftList.value = [...leftList.value]; //
}
}
//
function removeRecord(record: any) {
// rightSourceList
// if (rightSourceList.value.some(item => item.id === record.id)) {
// return;
// }
if (selectedRecordIds.value.includes(record.id)) {
selectedRecordIds.value = selectedRecordIds.value.filter(id => id !== record.id); // ID
leftList.value.push(record); //
rightNeedAddList.value = rightNeedAddList.value.filter(item => item.id !== record.id); //
rightNeedAddList.value = [...rightNeedAddList.value]; //
leftList.value = [...leftList.value]; //
}
}
//
function rowClassName(record: any) {
return selectedRecordIds.value.includes(record.id) ? 'selected-row' : '';
}
/**
* 一键全选将所有左侧数据移至右侧
*/
function selectAll() {
listByDS({
...queryParam,
pageNo: 1,
pageSize: -1,
}).then(res => {
const allRecords = res.records || [];
// rightSourceList
const unselectedRecords = allRecords.filter(record =>
!selectedRecordIds.value.includes(record.id)
// && !rightSourceList.value.some(item => item.id === record.id)
);
if (unselectedRecords.length) {
//
rightNeedAddList.value.push(...unselectedRecords);
// id id
selectedRecordIds.value.push(...unselectedRecords.map(r => r.id));
//
rightNeedAddList.value = [...rightNeedAddList.value];
selectedRecordIds.value = [...selectedRecordIds.value];
}
})
}
/**
* 全部移除将右侧数据移回左侧
*/
function removeAll() {
rightNeedAddList.value = []; //
// selectedRecordIds.value = rightSourceList.value?.map(d => d.id)
selectedRecordIds.value = []
}
//all/unsel
function sourceTypeChanged(val_) {
if (val_.target.value == 'all') {
//
queryParam.excludeIds = null
} else {
//
queryParam.excludeIds = selectedRecordIds.value.join(',')
}
reload()
}
//exist/needsync
function targetTypeChanged(val_) {
}
watch(
() => queryParam.directiveName,
(newVal) => {
reload()
}
);
function controlShowJSCom() {
showJSCom.value = false
setTimeout(() => {
showJSCom.value = true
}, 1000)
}
function cleanTargetSourceData() {
if (rightSourceList.value?.length) {
rightSourceList.value = []
selectedRecordIds.value = []
}
}
//
function syncFunc() {
if (props.targetChooseType == 'one') {
if (!targetOrg.value || !targetOrg.value.orgCode) {
createMessage.warning('请选择目标平台')
return
}
} else {
if (!props.targetOrgs.length) {
createMessage.warning('请选择目标平台')
return
}
}
if (!rightNeedAddList.value?.length) {
createMessage.warning('请选择需要同步的指令')
return
} else {
visible.value = true
}
}
//
function handleOk() {
let params = {}
if (props.targetChooseType == 'one') {
params = {
syncIds: rightNeedAddList.value
.filter(item => !rightSourceList.value.some(sourceItem => sourceItem.id === item.id))
.map(item => item.id)
.join(','),
upIds: rightNeedAddList.value
.filter(item => rightSourceList.value.some(sourceItem => sourceItem.id === item.id))
.map(item => item.id)
.join(','),
syncOrgCodes: targetOrg.value.orgCode,
syncOption: syncOption.value,
}
} else {
params = {
syncIds: rightNeedAddList.value.map(item => item.id).join(','),
upIds: '',
syncOrgCodes: props.targetOrgs.map(item => item.orgCode).join(','),
syncOption: syncOption.value,
}
}
syncDirective(sourceOrgInfo.value.orgCode, params)
createMessage.success('已开始自动同步!')
visible.value = false
}
//
function handleCancel() {
visible.value = false
}
//
function getNewCount() {
if (!rightNeedAddList.value || !rightSourceList.value) return 0;
return rightNeedAddList.value.filter(item =>
!rightSourceList.value.some(sourceItem => sourceItem.id === item.id)
).length;
}
//
function getUpdateCount() {
if (!rightNeedAddList.value || !rightSourceList.value) return 0;
return rightNeedAddList.value.filter(item =>
rightSourceList.value.some(sourceItem => sourceItem.id === item.id)
).length;
}
defineExpose({
init,
rightNeedAddList,
controlShowJSCom,
initTargetList,
cleanTargetSourceData,
syncFunc,
});
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust {
min-width: 100px !important;
}
.query-group-split-cust {
width: 30px;
display: inline-block;
text-align: center
}
.ant-form-item:not(.ant-form-item-with-help) {
margin-bottom: 16px;
height: 32px;
}
:deep(.ant-picker),
:deep(.ant-input-number) {
width: 100%;
}
}
audio::-webkit-media-controls-timeline {
display: none;
}
audio::-webkit-media-controls-current-time-display,
audio::-webkit-media-controls-time-remaining-display {
display: none;
}
.btnPrivate {
height: 34px;
margin-left: 4px;
}
/* 添加深度选择器确保样式能穿透组件 */
:deep(.ant-table-tbody) {
tr.selected-row {
td {
background-color: #e6f7ff !important;
}
&:hover td {
background-color: #e6f7ff !important;
}
}
}
:deep .ant-table-title {
display: none;
}
:deep .jeecg-basic-table-form-container .ant-form {
padding: 0px;
padding-right: 20px;
}
</style>

View File

@ -0,0 +1,202 @@
<template>
<a-spin :spinning="confirmLoading">
<JFormContainer :disabled="disabled">
<template #detail>
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol" name="ElderTagForm">
<a-row>
<a-col :span="24">
<a-form-item label="标签类型" v-bind="validateInfos.type" id="ElderTagForm-type" name="type">
<j-dict-select-tag v-model:value="formData.type" dictCode="elder_tag_type" placeholder="请选择标签类型"
allowClear :ignoreDisabled="true" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="标签名称" v-bind="validateInfos.tagName" id="ElderTagForm-tagName" name="tagName">
<a-input v-model:value="formData.tagName" placeholder="请输入标签名称" allow-clear></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="价格(元)" v-bind="validateInfos.price" id="ElderTagForm-price" name="price">
<a-input-number v-model:value="formData.price" placeholder="请输入价格" style="width: 100%" :min="0"
:max="99.99" :precision="2" @keydown="onPriceKeydown" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="图标" v-bind="validateInfos.pic" id="ElderTagForm-pic" name="pic">
<JImageUpload :fileMax="1" v-model:value="formData.pic"></JImageUpload>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="排序" v-bind="validateInfos.sort" id="ElderTagForm-sort" name="sort">
<a-input-number v-model:value="formData.sort" placeholder="请输入排序" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="是否启用" v-bind="validateInfos.izEnabled" id="ElderTagForm-izEnabled" name="izEnabled">
<j-dict-select-tag type='radio' v-model:value="formData.izEnabled" dictCode="iz_enabled"
placeholder="请选择是否启用"  allowClear />
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
</JFormContainer>
</a-spin>
</template>
<script lang="ts" setup>
import { ref, reactive, defineExpose, nextTick, defineProps, computed, onMounted } from 'vue';
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from '/@/hooks/web/useMessage';
import { getValueType } from '/@/utils';
import { saveOrUpdate } from '../ElderTag.api';
import { Form } from 'ant-design-vue';
import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import JImageUpload from '/@/components/Form/src/jeecg/components/JImageUpload.vue';
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({}) },
formBpm: { type: Boolean, default: true }
});
const onPriceKeydown = (e: KeyboardEvent) => {
const key = e.key;
//
if (['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab'].includes(key)) return;
//
if (!/[\d.]/.test(key)) {
e.preventDefault();
return;
}
const input = e.target as HTMLInputElement;
const { value, selectionStart: s, selectionEnd: t } = input;
const next = value.slice(0, s!) + key + value.slice(t!);
// 22
if (!/^\d{0,2}(?:\.\d{0,2})?$/.test(next)) {
e.preventDefault();
}
};
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
type: '',
tagName: '',
price: 0,
pic: '',
sort: 99,
izEnabled: '0',
});
const { createMessage } = useMessage();
const labelCol = ref<any>({ xs: { span: 24 }, sm: { span: 5 } });
const wrapperCol = ref<any>({ xs: { span: 24 }, sm: { span: 16 } });
const confirmLoading = ref<boolean>(false);
//
const validatorRules = reactive({
type: [{ required: true, message: '请输入标签类型!' },],
tagName: [{ required: true, message: '请输入标签名称!' },],
price: [{ required: true, message: '请输入价格!' }, { pattern: /^(([0-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!' },],
izEnabled: [{ required: true, message: '请输入是否启用!' },],
});
const { resetFields, validate, validateInfos } = useForm(formData, validatorRules, { immediate: false });
//
const disabled = computed(() => {
if (props.formBpm === true) {
if (props.formData.disabled === false) {
return false;
} else {
return true;
}
}
return props.formDisabled;
});
/**
* 新增
*/
function add() {
edit({});
}
/**
* 编辑
*/
function edit(record) {
nextTick(() => {
resetFields();
const tmpData = {};
Object.keys(formData).forEach((key) => {
if (record.hasOwnProperty(key)) {
tmpData[key] = record[key]
}
})
//
Object.assign(formData, tmpData);
});
}
/**
* 提交数据
*/
async function submitForm() {
try {
//
await validate();
} catch ({ errorFields }) {
if (errorFields) {
const firstField = errorFields[0];
if (firstField) {
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
}
}
return Promise.reject(errorFields);
}
confirmLoading.value = true;
const isUpdate = ref<boolean>(false);
//
let model = formData;
if (model.id) {
isUpdate.value = true;
}
//
for (let data in model) {
//
if (model[data] instanceof Array) {
let valueType = getValueType(formRef.value.getProps, data);
//
if (valueType === 'string') {
model[data] = model[data].join(',');
}
}
}
await saveOrUpdate(model, isUpdate.value)
.then((res) => {
if (res.success) {
createMessage.success(res.message);
emit('ok');
} else {
createMessage.warning(res.message);
}
})
.finally(() => {
confirmLoading.value = false;
});
}
defineExpose({
add,
edit,
submitForm,
});
</script>
<style lang="less" scoped>
.antd-modal-form {
padding: 14px;
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<a-drawer :title="title" width="50vw" v-model:visible="visible" :closable="true"
:footer-style="{ textAlign: 'right' }" @cancel="handleCancel">
<template #footer>
<a-button @click="handleCancel" style="margin-right: 8px;">关闭</a-button>
<a-button @click="handleOk" v-show="!disableSubmit">确认</a-button>
</template>
<ElderTagForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></ElderTagForm>
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import ElderTagForm from './ElderTagForm.vue'
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
import { useMessage } from '/@/hooks/web/useMessage';
import ElderTagRespositoryList from './ElderTagRespositoryList.vue'
import { syncElderTag } from '../ElderTag.api'
const mainOrgCode = ref('')
const dmRef = ref()
const title = ref<string>('');
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref();
const emit = defineEmits(['register', 'success']);
const dmVisible = ref(false)
const { createMessage, createConfirm } = useMessage();
const loading = ref(false)
function handleCancelDM() {
dmVisible.value = false
emit('success')
}
/**
* 新增
*/
function add() {
title.value = '新增';
visible.value = true;
nextTick(() => {
registerForm.value.add();
});
}
/**
* 编辑
* @param record
*/
function edit(record) {
title.value = disableSubmit.value ? '详情' : '编辑';
visible.value = true;
nextTick(() => {
registerForm.value.edit(record);
});
}
/**
* 确定按钮点击事件
*/
function handleOk() {
registerForm.value.submitForm();
}
/**
* form保存回调事件
*/
function submitCallback() {
handleCancel();
emit('success');
}
/**
* 取消按钮回调事件
*/
function handleCancel() {
visible.value = false;
}
function openDM(orgCode) {
dmVisible.value = true
mainOrgCode.value = orgCode
nextTick(() => {
dmRef.value?.init()
})
}
function handlePullDM() {
let selectedData = dmRef.value?.getSelectedIds()
if (!selectedData.count) {
createMessage.warning('未选择服务指令')
return
}
createConfirm({
iconType: 'warning',
title: '镜像确认',
content: '是否确认将<span style="font-weight:500;color:#efac0e;"> ' + selectedData.count + ' </span>条长者标签拉取到本平台?',
okText: '确认',
cancelText: '取消',
onOk: () => {
syncElderTag(mainOrgCode.value, { syncIds: selectedData.ids, })
createMessage.success('从标准标签库开始拉取')
// dmRef.value?.init()
handleCancelDM()
}
});
}
defineExpose({
add,
edit,
disableSubmit,
openDM
});
</script>
<style lang="less">
/**隐藏样式-modal确定按钮 */
.jee-hidden {
display: none !important;
}
</style>
<style lang="less" scoped></style>

View File

@ -0,0 +1,146 @@
<template>
<div>
<a-row>
<a-col v-for="(item, index) in orgTableList.records" :key="item.id" :xs="24" :sm="24"
:md="props.layout == 'full' ? 12 : 8" :lg="props.layout == 'full' ? 12 : 8" :xl="props.layout == 'full' ? 8 : 8"
:xxl="props.layout == 'full' ? 6 : 8" :xxxl="props.layout == 'full' ? 4 : 8"
:style="{ 'padding-right': ((index + 1) % 4 != 0) ? '14px' : '0px', 'padding-bottom': '14px' }">
<OrgCard :orgInfo="item" :layout="props.layout"
:is-selected="selectedOrgs.some(org => org.orgCode === item.orgCode)"
:is-directive-selected="directiveMainSelectedOrg?.orgCode === item.orgCode"
:is-elder-tag-main="etmOrg?.orgCode === item.orgCode" :show-detail="props.showDetail"
:clickable="props.showChoose || props.showDirectiveChoose" @click="handleCardClick" @detail="handleDetail" />
</a-col>
<a-col v-if="orgTableList.length == 0">
<div style="margin: 30px auto;">
<a-empty />
</div>
</a-col>
</a-row>
<div
style="float:right;bottom: 20px;z-index: 999;padding: 8px 16px;border-radius: 4px;display: flex;align-items: center;"
v-show="props.layout == 'full' && pageSize != -1">
<span style="margin-right: 10px;"> {{ orgTableList.total }} 条数据</span>
<Pagination showLessItems v-model:current="pageParams.pageNo" :pageSize="pageParams.pageSize" size="small"
show-quick-jumper :total="orgTableList.total" @change="reload" />
</div>
</div>
</template>
<script setup lang="ts" name="synchronization-directive2">
import { ref, reactive, onMounted } from 'vue'
import { Pagination } from 'ant-design-vue'
import { getOrgInfo } from '/@/views/admin/orgapplyinfo/OrgApplyInfo.api'
import OrgCard from '/@/components/OrgCard/OrgCardCom.vue'
const props = defineProps({
showChoose: { type: Boolean, default: false },
pageSize: { type: Number, default: 8 },
showDetail: { type: Boolean, default: false },
title: { type: String, default: '' },
allowMultipleSelection: { type: Boolean, default: false },
layout: { type: String, default: 'full' },
excludeOrgCode: { type: String, default: '' },
showDirectiveMain: { type: Boolean, default: false },
showDirectiveChoose: { type: Boolean, default: false },
showDMTip: { type: Boolean, default: false },
})
const emit = defineEmits(['handleOrgDetail', 'handleOrgChoose'])
const orgTableList = ref<any>({ records: [], total: 0 })
const queryParam = reactive<any>({})
const pageParams = ref({ pageNo: 1, pageSize: props.pageSize })
const directiveMainSelectedOrg = ref<any>(null)
const etmOrg = ref<any>('')
const selectedOrgs = ref<any[]>([])
function handleCardClick(item: any) {
if (props.showDirectiveChoose) {
directiveMainSelectedOrg.value = item
emit('handleOrgChoose', item)
}
if (props.showChoose) {
if (props.allowMultipleSelection) {
if (selectedOrgs.value.some(selected => selected.orgCode === item.orgCode)) {
selectedOrgs.value = selectedOrgs.value.filter(selected => selected.orgCode !== item.orgCode)
} else {
selectedOrgs.value.push(item)
}
} else {
selectedOrgs.value = [item]
}
}
}
function commitOrgsInfo() {
emit('handleOrgChoose', selectedOrgs.value)
}
function handleDetail(item: any) {
emit('handleOrgDetail', item)
}
function reload() {
directiveMainSelectedOrg.value = {}
queryParam.pageSize = pageParams.value.pageSize
queryParam.pageNo = pageParams.value.pageNo
queryParam.title = props.title
if (props.layout == 'half') {
queryParam.pageSize = -1
}
getOrgInfo(queryParam).then(res => {
res.records = res.records.filter(o => o.orgCode != props.excludeOrgCode)
orgTableList.value = res
if (props.showDirectiveChoose || props.showDMTip) {
const defaultSelected = res.records.find(item => item.izElderTagMain === '0')
if (defaultSelected) {
etmOrg.value = defaultSelected
emit('handleOrgChoose', defaultSelected)
}
}
})
}
function searchReset() {
queryParam.title = null
if (props.layout == 'half') {
queryParam.pageSize = -1
}
getOrgInfo(queryParam).then(res => {
res.records = res.records.filter(o => o.orgCode != props.excludeOrgCode)
orgTableList.value = res
})
}
function checkAllOrEmpty(isCheckAll = true) {
if (isCheckAll) {
orgTableList.value.records.forEach(item => {
if (!selectedOrgs.value.some(selected => selected.orgCode === item.orgCode)) {
selectedOrgs.value.push(item);
}
});
} else {
selectedOrgs.value = [];
}
emit('handleOrgChoose', selectedOrgs.value);
}
function resetSeleted(orgs: any[]) {
selectedOrgs.value = [...orgs]
}
onMounted(() => {
reload()
})
defineExpose({
reload,
searchReset,
selectedOrgs,
checkAllOrEmpty,
commitOrgsInfo,
resetSeleted
})
</script>

View File

@ -0,0 +1,396 @@
<template>
<div class="p-2">
<!--查询区域-->
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" @keyup.enter.native="searchQuery" :model="queryParam" :label-col="labelCol"
:wrapper-col="wrapperCol">
<a-row :gutter="24">
<a-col :lg="6">
<a-form-item name="title">
<template #label><span title="机构名称">机构名称</span></template>
<a-input placeholder="请输入机构名称" v-model:value="queryParam.title" allow-clear></a-input>
</a-form-item>
</a-col>
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset"
style="margin-left: 8px">重置</a-button>
</a-col>
<a-col :lg="12" style="text-align: right;">
<a-button type="primary" preIcon="ant-design:cloud-sync-outlined" @click="handleJingxiang"
style="margin-right: 10px;">镜像</a-button>
<a-button type="primary" preIcon="ant-design:file-text-twotone" @click="handleViewLogs"
style="margin-right: 10px;">日志</a-button>
<a-button type="primary" preIcon="ant-design:safety-certificate-twotone" @click="handleElderTagMainFunc"
style="margin-right: 10px;">标准标签库</a-button>
<!-- <a-badge :count="609" style="margin-right: 10px;"> -->
<a-button type="primary" preIcon="ant-design:eye-outlined" style="margin-right: 10px;"
@click="handleLookNewDirectives">新增标签</a-button>
<!-- </a-badge> -->
</a-col>
</a-row>
</a-form>
</div>
<OrgListCom ref="orgListComRef" :title="queryParam.title" @handleOrgDetail="handleDetail" :showDetail=true
:showDMTip="true">
</OrgListCom>
<ElderTagModal ref="configServiceDirectiveListModal" />
<SyncStepListModal ref="syncStepListModal" />
<!-- <a-modal v-model:visible="logsVisible" title="日志" width="90vw"
:bodyStyle="{ height: '70vh', display: 'flex', flexDirection: 'column', overflow: 'auto' }"
wrapClassName="org-list-modal" @cancel="handleCancelLogs">
<a-row>
<a-col :span="2" :push="22" style="margin-top: 15px;margin-left: 60px;">
<a-button type="primary" @click="handleRefreshLogs" title="刷新">
刷新
</a-button>
</a-col>
</a-row>
<template #footer>
<a-button @click="handleCancelLogs" type="primary">关闭</a-button>
</template>
<AsyncListComponent ref="logsRef"></AsyncListComponent>
</a-modal> -->
<a-drawer title="日志" width="85vw" v-model:visible="logsVisible"
:bodyStyle="{ height: '70vh', display: 'flex', flexDirection: 'column', overflow: 'auto' }"
wrapClassName="org-list-modal" @cancel="handleCancelLogs">
<a-row style="overflow-x: hidden !important; background-color: white;">
<a-col :span="2" :push="22" style="margin-top: 18px;margin-left: 30px;">
<a-button type="primary" @click="handleRefreshLogs" title="刷新">
刷新
</a-button>
</a-col>
<a-col :span="24">
<AsyncListComponent ref="logsRef" :type="'elderTag'"></AsyncListComponent>
</a-col>
</a-row>
<template #footer>
<a-button @click="handleCancelLogs" type="primary" style="float:right;">关闭</a-button>
</template>
</a-drawer>
<!-- 标准指令库 -->
<a-drawer v-model:visible="elderTagMainVisible" title="标准指令库" width="85vw" :footer-style="{ textAlign: 'right' }"
:bodyStyle="{ height: '70vh', display: 'flex', flexDirection: 'column', overflow: 'auto' }"
wrapClassName="org-list-modal" @cancel="handleCancelelderTagMain">
<template #footer>
<a-button @click="handleCancelelderTagMain" type="primary" style="margin-right: 10px;">关闭</a-button>
<a-button @click="handleAsyncelderTagMain" type="primary">确认</a-button>
</template>
<OrgListCom ref="elderTagMainComRef" :showElderTagMain=true :showDirectiveChoose="true"
@handleOrgDetail="handleDetail" :showDetail=true @handleOrgChoose="elderTagMainFunc">
</OrgListCom>
</a-drawer>
<!-- 新增标签 -->
<a-drawer v-model:visible="newElderTagVisible" title="新增标签" width="85vw" :footer-style="{ textAlign: 'right' }"
:bodyStyle="{ height: '80vh', display: 'flex', flexDirection: 'column', overflow: 'auto' }"
wrapClassName="org-list-modal" @cancel="handleCancelNewElderTag">
<template #footer>
<a-button @click="handleCancelNewElderTag" type="primary">关闭</a-button>
</template>
<div style="padding:0px 8px;">
<CanAddElderTagList ref="canAddElderTagRef" :elderTagMainOrgInfo="elderTagMainOrgInfo" :existETIds="existETIds"
@refreshExistIds="refreshDMExistedIds"></CanAddElderTagList>
</div>
</a-drawer>
</div>
</template>
<script setup name="synchronization-directive2" lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
//
import { list, asyncFunc, departList } from '@/views/services/serviceDirective/ConfigServiceDirective.api';
import { Pagination } from 'ant-design-vue';
import ElderTagModal from '/@/views/synchronization/eldertag/eldertag/components/ElderTagModal.vue';
import SyncStepListModal from '/@/views/synchronization/eldertag/syncStep/SyncStepListModal.vue';
//
import { getOrgInfo } from '/@/views/admin/orgapplyinfo/OrgApplyInfo.api';
//
import OrgListCom from '/@/views/synchronization/eldertag/orgCom/OrgListCom.vue'
//
import { useMessage } from '/@/hooks/web/useMessage';
import AsyncListComponent from '@/components/dataAsync/AsyncMainList0731.vue'
import { getElderTagMain, changeElderTagMain } from '/@/api/common/api'
import { idListByDS } from '/@/views/synchronization/eldertag/eldertag/ElderTag.api';
import CanAddElderTagList from '/@/views/synchronization/eldertag/canaddet/CanAddElderTagList.vue'
import { nextTick } from 'process';
const { createMessage } = useMessage()
const canAddElderTagRef = ref()
const newElderTagVisible = ref(false)
const elderTagMainComRef = ref();
const newDirectiveRef = ref()
const logsRef = ref()
const formRef = ref();
const configServiceDirectiveListModal = ref();
const syncStepListModal = ref();
const orgTableList = ref<any>([]);
const queryParam = reactive<any>({});
const pageParams = ref({ pageNo: 1, pageSize: 8 })
const orgListComRef = ref()
const logsVisible = ref(false)
const elderTagMainVisible = ref(false)
const { createConfirm } = useMessage();
const existETIds = ref([])//id
const elderTagMainOrgInfo = ref()
const labelCol = reactive({
xs: 24,
sm: 4,
xl: 6,
xxl: 4
});
const wrapperCol = reactive({
xs: 24,
sm: 20,
});
/**
* 镜像
*/
function handleJingxiang() {
syncStepListModal.value.init(null);
syncStepListModal.value.disableSubmit = true;
}
/**
* 详情
* @param record
*/
function handleDetail(record) {
configServiceDirectiveListModal.value.init(record);
configServiceDirectiveListModal.value.disableSubmit = true;
}
/**
* 查询
*/
function searchQuery() {
orgListComRef.value?.reload();
}
function reload() {
//
queryParam.pageSize = pageParams.value.pageSize;
queryParam.pageNo = pageParams.value.pageNo;
getOrgInfo(queryParam).then(res => {
orgTableList.value = res;
});
}
/**
* 重置
*/
function searchReset() {
queryParam.title = null
orgListComRef.value?.searchReset()
}
/**
* 日志
*/
function handleViewLogs() {
logsVisible.value = true
handleRefreshLogs()
}
function handleLookNewDirectives() {
newElderTagVisible.value = true
refreshDMExistedIds(elderTagMainOrgInfo.value, true)
}
//
function handleCancelLogs() {
logsVisible.value = false
}
//
function handleRefreshLogs() {
logsRef.value?.searchQuery()
}
/**
* 关闭新增指令
*/
function handleCancelNewElderTag() {
newElderTagVisible.value = false
}
/**
* 同步新增指令
*/
function handleAsyncNewDirective() {
// newDirectiveRef
}
/**
* 打开指令库
*/
function handleElderTagMainFunc() {
elderTagMainVisible.value = true
elderTagMainComRef.value?.reload();
}
/**
* 关闭指令库
*/
function handleCancelelderTagMain() {
elderTagMainVisible.value = false
}
//
function refreshDMExistedIds(dmOrgInfo, izReset = false, izQuery = true) {
idListByDS({ dataSourceCode: dmOrgInfo.orgCode }).then(res => {
existETIds.value = res.records
if (izReset) {
canAddElderTagRef.value?.searchReset()
} else {
canAddElderTagRef.value?.reload()
}
})
}
watch(elderTagMainOrgInfo, (newValue, oldValue) => {
refreshDMExistedIds(newValue)
}, { deep: true })
const tempDM = ref()
/**
* 指令库对应机构信息
*/
function elderTagMainFunc(orgInfo_) {
tempDM.value = orgInfo_
}
/**
* 确认指令库
*/
function handleAsyncelderTagMain() {
// createConfirm({
// iconType: 'warning',
// title: '',
// content: '' + tempDM.value.departName,
// okText: '',
// cancelText: '',
// onOk: () => {
elderTagMainOrgInfo.value = tempDM.value
changeElderTagMain(elderTagMainOrgInfo.value.orgCode).then(() => {
createMessage.success('标准指令库已变更')
handleCancelelderTagMain()
canAddElderTagRef.value?.reload()
orgListComRef.value?.reload()
}).catch(() => {
createMessage.error('指令库变更失败,请稍后再试')
})
// }
// });
}
//
function getElderTagMainOrgInfo() {
getElderTagMain().then(res => {
elderTagMainOrgInfo.value = res
})
}
//
onMounted(() => {
reload();
getElderTagMainOrgInfo()
orgListComRef.value?.reload();
});
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
margin-bottom: 18px;
.table-page-search-submitButtons {
display: block;
margin-bottom: 0px;
white-space: nowrap;
}
.query-group-cust {
min-width: 100px !important;
}
.query-group-split-cust {
width: 30px;
display: inline-block;
text-align: center
}
.ant-form-item:not(.ant-form-item-with-help) {
margin-bottom: 18px;
height: 32px;
}
:deep(.ant-picker),
:deep(.ant-input-number) {
width: 100%;
}
}
.cardTitle {
background: #1ea0fa;
width: 100%;
margin: -28px -24px;
padding-top: 15px;
border-radius: 5px 5px 0px 0px;
color: white;
height: 55px;
display: block;
position: absolute;
}
.zxClass {
font-size: 12px;
background: linear-gradient(to right, #1ea0fa, #017de9);
border-radius: 8px;
height: 25px;
color: white;
line-height: 25px;
}
.lxClass {
font-size: 14px;
background: linear-gradient(to right, #cccccc, #cccccc);
border-radius: 8px;
height: 35px;
color: white;
line-height: 35px;
}
.tbClass {
background: #f6f6f6;
padding: 8px;
border-radius: 5px;
}
.antTitle {
margin-top: 10px;
display: block;
font-size: 12px;
}
.ellipsis-one-lines {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
/* 限制文本为2行 */
overflow: hidden;
text-overflow: ellipsis;
}
.content-refresh-btn {
position: absolute;
top: 60px;
right: 20px;
z-index: 1;
}
</style>

View File

@ -0,0 +1,432 @@
<template>
<div class="container2 jeecg-basic-table-form-container">
<div class="left">
<a-card class="top">
<div class="source-platform">
<span class="section-title">源平台</span>
<a-button type="link" @click="showSourceOrgListModal" size="small">请选择</a-button>
</div>
<div class="selected-orgs" v-if="!!orgInfo.length">
<a-card :headStyle="{ height: '60px', padding: '0 24px' }" :bodyStyle="{ padding: '24px 24px 4px 24px' }">
<a-row style="font-weight: normal; margin-bottom: 12px;">
<a-col :span="18" style="font-size: 14px;">
<div>
<span style="font-weight: bold;">{{ orgInfo[0]?.departName }}</span>
</div>
</a-col>
<a-col :span="6" style="text-align: right;">
<div style="display: flex; align-items: center; justify-content: flex-end; gap: 8px;">
<div class="zxClass" style="min-width: 25px;">{{ orgInfo[0]?.orgCode }}</div>
</div>
</a-col>
</a-row>
<a-divider />
<p>加盟时间{{ orgInfo[0]?.franchiseTime?.substring(0, 10) }}</p>
<p>机构负责人{{ orgInfo[0]?.orgLeader }}</p>
<p>负责人电话{{ orgInfo[0]?.orgLeaderPhone }}</p>
<p class="ellipsis-one-lines" :title="orgInfo[0]?.comRegisterAddress">机构地址{{ orgInfo[0]?.comRegisterAddress
}}</p>
</a-card>
</div>
<a-empty v-else :description="'暂未选择'" />
</a-card>
<a-card class="bottom">
<div class="source-platform">
<span class="section-title">目标平台</span>
<div>
<a-radio-group v-model:value="targetChooseType" size="small" @change="targetChooseTypeChanged">
<a-radio-button value="one">指定</a-radio-button>
<a-radio-button value="multi">批量</a-radio-button>
</a-radio-group>
<a-divider type="vertical" style="background-color: #CDCDCF" />
<a-button type="link" @click="showTargetOrgListModal" size="small">请选择</a-button>
</div>
</div>
<div class="selected-orgs" ref="selectedOrgsContainer" style="height: 46vh; overflow: auto;"
v-if="!!syncOrgs.length">
<a-card v-for="orgItem of syncOrgs" class="org-card"
:class="{ 'selected-card': selectedTargetOrgs.some(org => org.orgCode === orgItem.orgCode), 'org-card': true }"
:headStyle="{ height: '60px', padding: '0 24px' }" :bodyStyle="{ padding: '24px 24px 4px 24px' }"
@click="handleTargetOrgChange(orgItem)">
<a-row style="font-weight: normal; margin-bottom: 12px;">
<a-col :span="18" style="font-size: 14px;">
<div>
<span style="font-weight: bold;">{{ orgItem.departName }}</span>
</div>
</a-col>
<a-col :span="6" style="text-align: right;">
<div style="display: flex; align-items: center; justify-content: flex-end; gap: 8px;">
<div class="zxClass" style="min-width: 25px;">{{ orgItem.orgCode }}</div>
</div>
</a-col>
</a-row>
<a-divider />
<p>加盟时间{{ orgItem?.franchiseTime?.substring(0, 10) }}</p>
<p>机构负责人{{ orgItem?.orgLeader }}</p>
<p>负责人电话{{ orgItem?.orgLeaderPhone }}</p>
<p class="ellipsis-one-lines" :title="orgItem?.comRegisterAddress">机构地址{{ orgItem?.comRegisterAddress
}}</p>
</a-card>
</div>
<a-empty style="margin-top: 50px;" v-else :description="'暂未选择'" />
</a-card>
</div>
<a-card class="right">
<div class="zljx-platform">
<span class="section-title">指令镜像</span>
<div class="directive-choose-wrapper">
<!-- <DirectiveChooseCom v-show="!!orgInfo.length" ref="directiveChooseRef" :targetChooseType="targetChooseType"
:targetOrgs="selectedTargetOrgs">
</DirectiveChooseCom> -->
</div>
</div>
</a-card>
<a-modal v-model:visible="sourceOrgListVisible" title="请选择源平台" width="90vw"
:bodyStyle="{ padding: '14px', height: '70vh', display: 'flex', flexDirection: 'column', overflow: 'auto' }"
wrapClassName="org-list-modal" @cancel="handleCancelSource">
<template #footer>
<a-button @click="handleCancelSource" type="primary">取消</a-button>
<a-button @click="handleGetSource" type="primary">确认</a-button>
</template>
<OrgListCom class="step-content" ref="sourceOrgListComRef" @handleOrgChoose="handleSourceOrgChoose"
:showChoose="true" />
</a-modal>
<a-modal v-model:visible="targetOrgListVisible" title="请选择目标平台(复选)" width="90vw" @cancel="handleCancelTarget"
:bodyStyle="{ padding: '14px', height: '70vh', display: 'flex', flexDirection: 'column', overflow: 'auto' }">
<template #footer>
<a-button @click="handleCancelTarget" type="primary">取消</a-button>
<a-button @click="handleGetTarget" type="primary">确认</a-button>
</template>
<OrgListCom class="step-content" ref="targetOrgListComRef" @handleOrgChoose="handleTargetOrgChoose"
:showChoose="true" :allowMultipleSelection="true" :pageSize="-1" :excludeOrgCode="orgInfo[0]?.orgCode" />
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, nextTick, watch } from 'vue';
import OrgListCom from '/@/views/synchronization/eldertag/orgCom/OrgListCom.vue';
// import DirectiveChooseCom from '/@/views/synchronization/eldertag/serviceDirective/DirectiveChooseCom.vue'
const sourceOrgListVisible = ref(false);
const targetOrgListVisible = ref(false);
const sourceOrgListComRef = ref();
const targetOrgListComRef = ref();
const orgInfo = ref([])
const syncOrgs = ref([])
const directiveChooseRef = ref()
const selectedTargetOrgs = ref([])//
const targetChooseType = ref('one')
const selectedOrgsContainer = ref<HTMLElement>();
const emit = defineEmits(['changeSyncText']);
//
function showSourceOrgListModal() {
sourceOrgListComRef.value?.reload()
targetOrgListComRef.value?.reload()
sourceOrgListVisible.value = true;
}
//
function showTargetOrgListModal() {
sourceOrgListComRef.value?.reload()
targetOrgListComRef.value?.reload()
targetOrgListVisible.value = true;
}
//
function resetTargetOrgs(orgInfo_) {
//
const syncOrgsIndex = syncOrgs.value.findIndex(
org => org.orgCode === orgInfo_.orgCode
);
if (syncOrgsIndex >= 0) {
//
syncOrgs.value.splice(syncOrgsIndex, 1);
}
syncOrgs.value = [...syncOrgs.value];
//
const selectedTargetOrgsIndex = selectedTargetOrgs.value.findIndex(
org => org.orgCode === orgInfo_.orgCode
);
if (selectedTargetOrgsIndex >= 0) {
//
selectedTargetOrgs.value.splice(selectedTargetOrgsIndex, 1);
}
selectedTargetOrgs.value = [...selectedTargetOrgs.value];
//""""
if (targetChooseType.value == 'one' && !!syncOrgs.value?.length && selectedTargetOrgsIndex >= 0) {
selectedTargetOrgs.value = [{ ...syncOrgs.value?.[0] }]
//
nextTick(() => {
if (selectedOrgsContainer.value) {
selectedOrgsContainer.value.scrollTop = 0;
}
});
}
}
//
function handleSourceOrgChoose(orgInfo_) {
//
resetTargetOrgs(orgInfo_[0])
orgInfo.value = orgInfo_
//
targetOrgListComRef.value?.resetSeleted(syncOrgs.value)
directiveChooseRef.value?.controlShowJSCom()
//
if (selectedTargetOrgs.value.length) {
if (targetChooseType.value == 'one') {
directiveChooseRef?.value?.init({ orgInfo: orgInfo.value[0] })
directiveChooseRef.value?.initTargetList(selectedTargetOrgs.value[0])
}
} else {
directiveChooseRef?.value?.init({ orgInfo: orgInfo.value[0] })
}
}
//
function handleTargetOrgChoose(orgInfo_) {
if (!syncOrgs.value || syncOrgs.value.length == 0) {
if (targetChooseType.value == 'one' && orgInfo_.length > 0) {
selectedTargetOrgs.value = [{ ...orgInfo_[0] }]
directiveChooseRef.value?.initTargetList(orgInfo_[0])
}
}
syncOrgs.value = orgInfo_
}
function handleCancelSource() {
sourceOrgListVisible.value = false;
sourceOrgListComRef.value?.resetSeleted(orgInfo.value)
}
function handleCancelTarget() {
targetOrgListVisible.value = false;
targetOrgListComRef.value?.resetSeleted(syncOrgs.value)
}
///
function handleTargetOrgChange(org_) {
if (targetChooseType.value == 'one') {
selectedTargetOrgs.value = [{ ...org_ }]
directiveChooseRef.value?.initTargetList(org_)
} else {
//
const index = selectedTargetOrgs.value.findIndex(
org => org.orgCode === org_.orgCode
);
if (index >= 0) {
//
selectedTargetOrgs.value.splice(index, 1);
} else {
//
selectedTargetOrgs.value.push(org_);
}
//
selectedTargetOrgs.value = [...selectedTargetOrgs.value];
// directiveChooseRef.value?.cleanTargetSourceData()
}
}
// /
function targetChooseTypeChanged(val_) {
if (val_.target.value == 'one' && !!syncOrgs.value?.length) {
selectedTargetOrgs.value = [{ ...syncOrgs.value?.[0] }]
//
nextTick(() => {
if (selectedOrgsContainer.value) {
selectedOrgsContainer.value.scrollTop = 0;
}
});
}
emit('changeSyncText', val_.target.value)
}
//
function handleGetSource() {
sourceOrgListComRef.value?.commitOrgsInfo()
handleCancelSource()
}
//
function handleGetTarget() {
targetOrgListComRef.value?.commitOrgsInfo()
handleCancelTarget()
}
function syncFunc() {
directiveChooseRef.value?.syncFunc()
}
defineExpose({
syncFunc
});
</script>
<style lang="less" scoped>
.jeecg-basic-table-form-container {
padding: 0;
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
.query-group-cust {
min-width: 100px !important;
}
.query-group-split-cust {
width: 30px;
display: inline-block;
text-align: center
}
.ant-form-item:not(.ant-form-item-with-help) {
margin-bottom: 16px;
height: 32px;
}
:deep(.ant-picker),
:deep(.ant-input-number) {
width: 100%;
}
}
.container2 {
display: flex;
margin: 1%;
max-height: 85vh;
}
.left {
display: flex;
flex-direction: column;
width: 18%;
margin-right: 1%;
}
.source-platform {
display: flex;
align-items: center;
justify-content: space-between;
}
.zljx-platform {
display: flex;
flex-direction: column;
/* 改为垂直排列 */
gap: 8px;
/* 添加间距 */
.section-title {
font-size: 14px;
font-weight: 600;
color: #333;
position: relative;
padding-left: 12px;
}
.directive-choose-wrapper {
width: 100%;
/* 可以根据需要添加其他样式 */
}
}
.section-title {
font-size: 14px;
font-weight: 600;
color: #333;
position: relative;
padding-left: 12px;
}
.left .top {
flex: 0 0 28%;
margin-bottom: 1%;
}
.left .bottom {
flex: 1;
margin-bottom: 1%;
}
.right {
flex: 1;
width: 80%;
max-height: 85vh;
}
:deep .ant-card-body {
padding: 12px;
}
.step-content {
overflow: auto;
height: 70vh;
}
.zxClass {
font-size: 12px;
background: linear-gradient(to right, #1ea0fa, #017de9);
border-radius: 8px;
height: 25px;
color: white;
line-height: 25px;
padding: 0 8px;
/* 增加内边距 */
flex-shrink: 0;
/* 防止被压缩 */
}
.tbClass {
background: #f6f6f6;
padding: 8px;
border-radius: 5px;
}
.antTitle {
margin-top: 10px;
display: block;
font-size: 12px;
}
.ellipsis-one-lines {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
.selected-card {
border: 2px solid #1890ff;
box-shadow: 0 0 8px rgba(24, 144, 255, 0.3);
}
.directive-selected-card {
border: 2px solid #1890FF;
box-shadow: 0 0 8px rgba(37, 149, 255, 0.3);
}
.org-card {
margin-top: 8px;
&:hover {
border-color: #55a9f8;
/* 这是悬停时的蓝色边框 */
box-shadow: 0 2px 8px rgba(37, 149, 255, 0.3);
/* 这是悬停时的淡蓝色阴影 */
}
}
:deep .ant-divider {
margin: 0 0 8px 0;
}
</style>

View File

@ -0,0 +1,124 @@
<template>
<!-- <j-modal :title="title" :visible="visible" :fullscreen="true" width="100vw" :bodyStyle="{ padding: 0 }"
:maskClosable="false" :keyboard="false" wrapClassName="modal-fullscreen" @cancel="handleCancel">
<template #footer>
<a-button @click="handleCancel">关闭</a-button>
<a-button @click="handleSyncFunc">{{syncText}}</a-button>
<a-button @click="previousStep"
v-show="!!registerForm && (registerForm?.stepVal == 1 || registerForm?.stepVal == 2 || registerForm?.stepVal == 3)">上一步</a-button>
<a-button @click="nextStep"
v-show="!!registerForm && (registerForm?.stepVal == 0 || registerForm?.stepVal == 1 || registerForm?.stepVal == 2)">下一步</a-button>
<a-button @click="registerForm?.syncFunc" type="primary"
v-show="!!registerForm && registerForm?.stepVal == 3">确认</a-button>
</template>
<SyncStepList ref="registerForm" v-if="visible" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"
:fullscreen="true" style="height:100vh;" @closeModal="closeModal" @changeSyncText="changeSyncText"/>
</j-modal> -->
<a-drawer :title="title" width="100vw" v-model:visible="visible" :closable="true" :bodyStyle="{ padding: 0 }" :maskClosable="false" :keyboard="false"
:footer-style="{ textAlign: 'right' }" @close="handleCancel">
<SyncStepList ref="registerForm" v-if="visible" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"
:fullscreen="true" style="height:100vh;" @closeModal="closeModal" @changeSyncText="changeSyncText"/>
<template #footer>
<a-button @click="handleCancel" style="margin-right: 10px;">关闭</a-button>
<a-button @click="handleSyncFunc">{{syncText}}</a-button>
<a-button @click="previousStep"
v-show="!!registerForm && (registerForm?.stepVal == 1 || registerForm?.stepVal == 2 || registerForm?.stepVal == 3)">上一步</a-button>
<a-button @click="nextStep"
v-show="!!registerForm && (registerForm?.stepVal == 0 || registerForm?.stepVal == 1 || registerForm?.stepVal == 2)">下一步</a-button>
<a-button @click="registerForm?.syncFunc" type="primary"
v-show="!!registerForm && registerForm?.stepVal == 3">确认</a-button>
</template>
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose, defineProps } from 'vue';
import SyncStepList from './SyncStepList.vue';
import JModal from '/@/components/Modal/src/JModal/JModal.vue';
const props = defineProps({
sysUrlValue: { type: String, default: '' },
});
const emit = defineEmits(['register', 'success']);
const title = ref<string>('');
const visible = ref<boolean>(false);
const disableSubmit = ref<boolean>(false);
const registerForm = ref<InstanceType<typeof SyncStepList>>();
const syncText = ref('同步')
function changeSyncText(v_){
if(v_ == 'one'){
syncText.value = '同步'
}else{
syncText.value = '批量同步'
}
}
function handleSyncFunc(){
registerForm.value?.syncFunc()
}
/**
* 编辑或初始化弹窗
*/
function init(record: any) {
title.value = '镜像';
visible.value = true;
nextTick(() => {
registerForm.value?.init(record);
});
}
/**
* 子组件提交完成回调
*/
function submitCallback() {
visible.value = false;
emit('success');
}
/**
* 上一步
*/
function previousStep() {
registerForm.value?.changeStepVal(false)
}
/**
* 下一步
*/
function nextStep() {
registerForm.value?.changeStepVal(true)
}
/**
* 取消按钮回调
*/
function handleCancel() {
visible.value = false;
}
function closeModal() {
visible.value = false;
}
defineExpose({
init,
disableSubmit,
});
</script>
<style lang="less" scoped>
.modal-fullscreen :deep(.ant-modal) {
max-width: 100vw !important;
width: 100vw !important;
top: 0 !important;
margin: 0 !important;
}
.modal-fullscreen :deep(.ant-modal-body) {
padding: 0 !important;
height: 100vh !important;
}
</style>