Compare commits

...

2 Commits

29 changed files with 1410 additions and 1483 deletions

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1743498900165" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="32026" width="256" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M491.290329 814.099433 172.772972 485.118769l81.634252-66.460668 184.189999 146.68992c75.488275-91.145883 243.049548-271.999904 474.234885-415.849126l19.469424 45.569872C720.102618 393.022235 546.356482 671.686932 491.290329 814.099433L491.290329 814.099433 491.290329 814.099433 491.290329 814.099433zM893.493667 454.874955c3.400446 20.849864 5.203512 42.24515 5.203512 64.047712 0 217.08213-175.971827 393.063167-393.06419 393.063167-217.055524 0-393.063167-175.981037-393.063167-393.063167 0-217.065757 176.007643-393.059074 393.063167-393.059074 52.423977 0 102.419647 10.275018 148.147108 28.90533L653.780097 76.133981c-47.586808-15.926738-97.265254-23.992437-148.147108-23.992437-62.9671 0-124.107599 12.342096-181.694155 36.7019-55.605436 23.538089-105.513102 57.198723-148.365072 100.008738-42.836621 42.850947-76.481905 92.748381-100.010785 148.365072C51.220568 394.814044 38.85289 455.934077 38.85289 518.922666c0 62.978357 12.367679 124.113739 36.710087 181.720761 23.528879 55.584969 57.173141 105.497753 100.010785 148.343583 42.850947 42.841737 92.759637 76.481905 148.365072 100.010785 57.586556 24.343431 118.732172 36.699853 181.694155 36.699853 62.989613 0 124.145461-12.356422 181.730994-36.699853 55.585993-23.528879 105.488543-57.162908 148.334373-100.010785 42.850947-42.845831 76.501348-92.759637 100.010785-148.343583 24.373107-57.605999 36.70497-118.742405 36.70497-181.720761 0-21.583574-1.436722-42.944068-4.328585-64.047712L893.493667 454.874955 893.493667 454.874955 893.493667 454.874955zM893.493667 454.874955" fill="#81C784" p-id="32027"></path></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,140 @@
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="字典列表" width="800px">
<BasicTable @register="registerTable" :rowClassName="getRowClassName">
<template #tableTitle>
<a-button type="primary" @click="handleCreate"> 新增</a-button>
</template>
<template v-slot:bodyCell="{column, record, index}">
<template v-if="column.dataIndex ==='action'">
<TableAction :actions="getTableAction(record)" />
</template>
</template>
</BasicTable>
</BasicDrawer>
<DictItemModal @register="registerModal" @success="reload" :dictId="dictId" />
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicDrawer, useDrawerInner } from '/src/components/Drawer';
import { BasicTable, useTable, TableAction } from '/src/components/Table';
import { useModal } from '/src/components/Modal';
import { useDesign } from '/@/hooks/web/useDesign';
import DictItemModal from './DictItemModal.vue';
import { dictItemColumns, dictItemSearchFormSchema } from '../dict.data';
import { itemList, deleteItem } from '../dict.api';
import { ColEx } from '/@/components/Form/src/types';
const { prefixCls } = useDesign('row-invalid');
const dictId = ref('');
//model
const [registerModal, { openModal }] = useModal();
const [registerDrawer] = useDrawerInner(async (data) => {
dictId.value = data.id;
setProps({ searchInfo: { dictId: unref(dictId) } });
reload();
});
//
const adaptiveColProps: Partial<ColEx> = {
xs: 24, // <576px
sm: 24, // 576px
md: 24, // 768px
lg: 12, // 992px
xl: 12, // 1200px
xxl: 8, // 1600px
};
const [registerTable, { reload, setProps }] = useTable({
//rowKey
rowKey:'dictId',
api: itemList,
columns: dictItemColumns,
formConfig: {
baseColProps: adaptiveColProps,
labelAlign: 'right',
labelCol: {
offset: 1,
xs: 24,
sm: 24,
md: 24,
lg: 9,
xl: 7,
xxl: 4,
},
wrapperCol: {},
schemas: dictItemSearchFormSchema,
autoSubmitOnEnter: true,
actionColOptions: {
span: 8
}
},
striped: true,
useSearchForm: true,
bordered: true,
showIndexColumn: false,
canResize: false,
immediate: false,
actionColumn: {
width: 100,
title: '操作',
dataIndex: 'action',
//slots: { customRender: 'action' },
fixed: undefined,
},
});
/**
* 新增
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑
*/
function handleEdit(record) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 删除
*/
async function handleDelete(record) {
await deleteItem({ id: record.id }, reload);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
];
}
function getRowClassName(record) {
return record.status == 1 ? prefixCls : '';
}
</script>
<style scoped lang="less">
@prefix-cls: ~'@{namespace}-row-invalid';
:deep(.@{prefix-cls}) {
background: #f4f4f4;
color: #bababa;
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit" width="800px">
<!-- update-begin---author:wangshuai---date:2023-10-23---for:QQYUN-6804后台模式字典没有颜色配置--- -->
<BasicForm @register="registerForm" >
<template #itemColor="{ model, field }">
<div class="item-tool">
<div
v-for="(item,index) in Colors"
:style="{ color: item[0] }"
:class="model.itemColor===item[0]?'item-active':''"
class="item-color"
@click="itemColorClick(item)">
<div class="item-color-border"></div>
<div class="item-back" :style="{ background: item[0] }"></div>
</div>
</div>
</template>
</BasicForm>
<!-- update-end---author:wangshuai---date:2023-10-23---for:QQYUN-6804后台模式字典没有颜色配置--- -->
</BasicModal>
</template>
<script lang="ts" setup>
import { defineProps, ref, computed, unref, reactive } from 'vue';
import { BasicModal, useModalInner } from '/src/components/Modal';
import { BasicForm, useForm } from '/src/components/Form';
import { itemFormSchema } from '../dict.data';
import { saveOrUpdateDictItem } from '../dict.api';
import { Colors } from '/@/utils/dict/DictColors.js'
// Emits
const emit = defineEmits(['success', 'register']);
const props = defineProps({ dictId: String });
const isUpdate = ref(true);
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: itemFormSchema,
showActionButtonGroup: false,
mergeDynamicData: props,
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 },
},
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//
await setFieldsValue({
...data.record,
});
}
});
//
const getTitle = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//
async function handleSubmit() {
try {
const values = await validate();
values.dictId = props.dictId;
setModalProps({ confirmLoading: true });
//
await saveOrUpdateDictItem(values, isUpdate.value);
//
closeModal();
//
emit('success');
} finally {
setModalProps({ confirmLoading: false });
}
}
/**
* 字典颜色点击事件
*
* @param index
* @param item
* @param model
*/
function itemColorClick(item) {
console.log(item)
setFieldsValue({ itemColor: item[0] })
}
</script>
<style lang="less" scoped>
/*begin 字典颜色配置样式*/
.item-tool{
display: flex;
flex-wrap: wrap;
.item-color{
width: 18px;
display: flex;
justify-content: center;
cursor: pointer;
align-items: center;
margin-right: 10px;
}
.item-back{
width: 18px;
height: 18px;
border-radius: 50%;
}
}
.item-color-border{
visibility: hidden;
}
.item-active .item-color-border{
visibility: visible;
position: absolute;
border: 1px solid;
width: 24px;
height: 24px;
border-radius: 50%;
}
/*end 字典颜色配置样式*/
</style>

View File

@ -0,0 +1,52 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" width="550px" @ok="handleSubmit">
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicModal, useModalInner } from '/src/components/Modal';
import { BasicForm, useForm } from '/src/components/Form';
import { formSchema } from '../dict.data';
import { saveOrUpdateDict } from '../dict.api';
// Emits
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const rowId = ref('');
//
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
schemas: formSchema,
showActionButtonGroup: false,
});
//
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({ confirmLoading: false, minHeight: 80 });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
rowId.value = data.record.id;
//
await setFieldsValue({
...data.record,
});
}
});
//
const getTitle = computed(() => (!unref(isUpdate) ? '新增字典' : '编辑字典'));
//
async function handleSubmit() {
try {
let values = await validate();
setModalProps({ confirmLoading: true });
//
await saveOrUpdateDict(values, isUpdate.value);
//
closeModal();
//
emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } });
} finally {
setModalProps({ confirmLoading: false });
}
}
</script>

View File

@ -0,0 +1,141 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="字典回收站" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-dropdown v-if="checkedKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
批量删除
</a-menu-item>
<a-menu-item key="2" @click="batchHandleRevert">
<Icon icon="ant-design:redo-outlined"></Icon>
批量取回
</a-menu-item>
</a-menu>
</template>
<a-button
>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, toRaw } from 'vue';
import { BasicModal, useModalInner } from '/src/components/Modal';
import { BasicTable, useTable, TableAction } from '/src/components/Table';
import { recycleBincolumns } from '../dict.data';
import { getRecycleBinList, putRecycleBin, deleteRecycleBin, batchPutRecycleBin, batchDeleteRecycleBin } from '../dict.api';
// Emits
const emit = defineEmits(['success', 'register']);
const checkedKeys = ref<Array<string | number>>([]);
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const [registerTable, { reload }] = useTable({
rowKey: 'id',
api: getRecycleBinList,
columns: recycleBincolumns,
striped: true,
useSearchForm: false,
showTableSetting: false,
clickToRowSelect: false,
bordered: true,
showIndexColumn: false,
pagination: false,
tableSetting: { fullScreen: true },
canResize: false,
actionColumn: {
width: 100,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: undefined,
},
});
// update-begin--author:liaozhiyang---date:20240709---forTV360X-1663
/**
* 选择列配置
*/
const rowSelection = {
type: 'checkbox',
columnWidth: 50,
selectedRowKeys: checkedKeys,
onChange: onSelectChange,
};
/**
* 选择事件
*/
function onSelectChange(selectedRowKeys: (string | number)[]) {
checkedKeys.value = selectedRowKeys;
}
// update-end--author:liaozhiyang---date:20240709---forTV360X-1663
/**
* 还原事件
*/
async function handleRevert(record) {
await putRecycleBin(record.id, reload);
emit('success');
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteRecycleBin(record.id, reload);
}
/**
* 批量还原事件
*/
function batchHandleRevert() {
batchPutRecycleBin({ ids: toRaw(checkedKeys.value).join(',') }, () => {
// update-begin--author:liaozhiyang---date:20240709---forTV360X-1663
reload();
checkedKeys.value = [];
emit('success');
// update-end--author:liaozhiyang---date:20240709---forTV360X-1663
});
}
/**
* 批量删除事件
*/
function batchHandleDelete() {
batchDeleteRecycleBin({ ids: toRaw(checkedKeys.value).join(',') }, () => {
// update-begin--author:liaozhiyang---date:20240709---forTV360X-1663
checkedKeys.value = [];
reload();
// update-end--author:liaozhiyang---date:20240709---forTV360X-1663
});
}
//
function getTableAction(record) {
return [
{
label: '取回',
icon: 'ant-design:redo-outlined',
popConfirm: {
title: '是否确认取回',
confirm: handleRevert.bind(null, record),
},
},
{
label: '彻底删除',
icon: 'ant-design:scissor-outlined',
color: 'error',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
},
},
];
}
</script>

View File

@ -0,0 +1,156 @@
import { defHttp } from '/@/utils/http/axios';
import { Modal } from 'ant-design-vue';
enum Api {
list = '/nu/dict/list',
save = '/nu/dict/add',
edit = '/nu/dict/edit',
duplicateCheck = '/sys/duplicate/check',
deleteDict = '/nu/dict/delete',
deleteBatch = '/nu/dict/deleteBatch',
importExcel = '/nu/dict/importExcel',
exportXls = '/nu/dict/exportXls',
recycleBinList = '/nu/dict/deleteList',
putRecycleBin = '/nu/dict/back',
batchPutRecycleBin = '/nu/dict/putRecycleBin',
batchDeleteRecycleBin = '/nu/dict/deleteRecycleBin',
deleteRecycleBin = '/nu/dict/deletePhysic',
itemList = '/nu/dictItem/list',
deleteItem = '/nu/dictItem/delete',
itemSave = '/nu/dictItem/add',
itemEdit = '/nu/dictItem/edit',
dictItemCheck = '/nu/dictItem/dictItemCheck',
refreshCache = '/nu/dict/refleshCache',
queryAllDictItems = '/nu/dict/queryAllDictItems',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
* @param params
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) => defHttp.get({ url: Api.list, params });
/**
*
*/
export const deleteDict = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteDict, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const batchDeleteDict = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
},
});
};
/**
*
* @param params
*/
export const saveOrUpdateDict = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const duplicateCheck = (params) => defHttp.get({ url: Api.duplicateCheck, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const getRecycleBinList = (params) => defHttp.get({ url: Api.recycleBinList, params });
/**
*
* @param params
*/
export const batchPutRecycleBin = (params, handleSuccess) => {
return defHttp.put({ url: Api.batchPutRecycleBin, params}).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const putRecycleBin = (id, handleSuccess) => {
return defHttp.put({ url: Api.putRecycleBin + `/${id}` }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const batchDeleteRecycleBin = (params, handleSuccess) => {
return defHttp.delete({ url: `${Api.batchDeleteRecycleBin}?ids=${params.ids}`}).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const deleteRecycleBin = (id, handleSuccess) => {
return defHttp.delete({ url: Api.deleteRecycleBin + `/${id}` }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
/**
*
* @param params
*/
export const deleteItem = (params, handleSuccess) => {
return defHttp.delete({ url: Api.deleteItem, params }, { joinParamsToUrl: true }).then(() => {
handleSuccess();
});
};
/**
*
* @param params
*/
export const saveOrUpdateDictItem = (params, isUpdate) => {
let url = isUpdate ? Api.itemEdit : Api.itemSave;
return defHttp.post({ url: url, params });
};
/**
*
* @param params
*/
export const dictItemCheck = (params) => defHttp.get({ url: Api.dictItemCheck, params }, { isTransformResponse: false });
/**
*
* @param params
*/
export const refreshCache = () => defHttp.get({ url: Api.refreshCache }, { isTransformResponse: false });
/**
*
* @param params
*/
export const queryAllDictItems = () => defHttp.get({ url: Api.queryAllDictItems }, { isTransformResponse: false });

View File

@ -0,0 +1,203 @@
import { BasicColumn } from '/@/components/Table';
import { FormSchema } from '/@/components/Table';
import { dictItemCheck } from './dict.api';
import { rules } from '/@/utils/helper/validator';
import { h } from "vue";
export const columns: BasicColumn[] = [
{
title: '字典名称',
dataIndex: 'dictName',
width: 240,
},
{
title: '字典编码',
dataIndex: 'dictCode',
width: 240,
},
{
title: '描述',
dataIndex: 'description',
// width: 120
},
];
export const recycleBincolumns: BasicColumn[] = [
{
title: '字典名称',
dataIndex: 'dictName',
width: 120,
},
{
title: '字典编码',
dataIndex: 'dictCode',
width: 120,
},
{
title: '描述',
dataIndex: 'description',
width: 120,
},
];
export const searchFormSchema: FormSchema[] = [
{
label: '字典名称',
field: 'dictName',
component: 'JInput',
colProps: { span: 6 },
},
{
label: '字典编码',
field: 'dictCode',
component: 'JInput',
colProps: { span: 6 },
},
];
export const formSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '字典名称',
field: 'dictName',
required: true,
component: 'Input',
},
{
label: '字典编码',
field: 'dictCode',
component: 'Input',
dynamicDisabled: ({ values }) => {
return !!values.id;
},
dynamicRules: ({ model, schema }) => rules.duplicateCheckRule('sys_dict', 'dict_code', model, schema, true),
},
{
label: '描述',
field: 'description',
component: 'Input',
},
];
export const dictItemColumns: BasicColumn[] = [
{
title: '名称',
dataIndex: 'itemText',
width: 80,
},
{
title: '数据值',
dataIndex: 'itemValue',
width: 80,
},
{
title: '字典颜色',
dataIndex: 'itemColor',
width: 80,
align:'center',
customRender:({ text }) => {
return h('div', {
style: {"background": text, "width":"18px","height":"18px","border-radius":"50%","margin":"0 auto"}
})
}
},
];
export const dictItemSearchFormSchema: FormSchema[] = [
{
label: '名称',
field: 'itemText',
component: 'Input',
},
{
label: '状态',
field: 'status',
component: 'JDictSelectTag',
componentProps: {
dictCode: 'dict_item_status',
stringToNumber: true,
},
},
];
export const itemFormSchema: FormSchema[] = [
{
label: '',
field: 'id',
component: 'Input',
show: false,
},
{
label: '名称',
field: 'itemText',
required: true,
component: 'Input',
},
{
label: '数据值',
field: 'itemValue',
component: 'Input',
dynamicRules: ({ values, model }) => {
return [
{
required: true,
validator: (_, value) => {
if (!value) {
return Promise.reject('请输入数据值');
}
if (new RegExp("[`~!@#$^&*()=|{}'.<>《》/?!¥()—【】‘;:”“。,、?]").test(value)) {
return Promise.reject('数据值不能包含特殊字符!');
}
return new Promise<void>((resolve, reject) => {
let params = {
dictId: values.dictId,
id: model.id,
itemValue: value,
};
dictItemCheck(params)
.then((res) => {
res.success ? resolve() : reject(res.message || '校验失败');
})
.catch((err) => {
reject(err.message || '验证失败');
});
});
},
},
];
},
},
{
label: '颜色值',
field: 'itemColor',
component: 'Input',
slot:'itemColor'
},
{
label: '描述',
field: 'description',
component: 'Input',
},
{
field: 'sortOrder',
label: '排序',
component: 'InputNumber',
defaultValue: 1,
},
{
field: 'status',
label: '是否启用',
defaultValue: 0,
component: 'JDictSelectTag',
componentProps: {
type: 'radioButton',
dictCode: 'dict_item_status',
stringToNumber: true,
},
},
];

View File

@ -0,0 +1,196 @@
<template>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-button type="primary" @click="handlerRefreshCache" preIcon="ant-design:sync-outlined"> 刷新缓存</a-button>
<a-button type="primary" @click="openRecycleModal(true)" preIcon="ant-design:hdd-outlined"> 回收站</a-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
<!--字典弹窗-->
<DictModal @register="registerModal" @success="handleSuccess" />
<!--字典配置抽屉-->
<DictItemList @register="registerDrawer" />
<!--回收站弹窗-->
<DictRecycleBinModal @register="registerModal1" @success="reload" />
</template>
<script lang="ts" name="system-dict" setup>
//ts
import { ref, computed, unref } from 'vue';
import { BasicTable, TableAction } from '/src/components/Table';
import { useDrawer } from '/src/components/Drawer';
import { useModal } from '/src/components/Modal';
import DictItemList from './components/DictItemList.vue';
import DictModal from './components/DictModal.vue';
import DictRecycleBinModal from './components/DictRecycleBinModal.vue';
import { useMessage } from '/src/hooks/web/useMessage';
import { removeAuthCache, setAuthCache } from '/src/utils/auth';
import { columns, searchFormSchema } from './dict.data';
import { list, deleteDict, batchDeleteDict, getExportUrl, getImportUrl, refreshCache, queryAllDictItems } from './dict.api';
import { DB_DICT_DATA_KEY } from '/src/enums/cacheEnum';
import { useUserStore } from '/@/store/modules/user';
const { createMessage } = useMessage();
//model
const [registerModal, { openModal }] = useModal();
//drawer
const [registerDrawer, { openDrawer }] = useDrawer();
import { useListPage } from '/@/hooks/system/useListPage';
//model
const [registerModal1, { openModal: openRecycleModal }] = useModal();
//
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
designScope: 'dict-template',
tableProps: {
title: '数据字典',
api: list,
columns: columns,
formConfig: {
schemas: searchFormSchema,
},
actionColumn: {
width: 240,
},
},
//update-begin---author:wangshuai ---date:20220616 for[issues/I5AMDD]/ export.url/import.url ------------
exportConfig: {
name: '数据字典列表',
url: getExportUrl,
},
importConfig: {
url: getImportUrl,
},
//update-end---author:wangshuai ---date:20220616 for[issues/I5AMDD]/ export.url/import.url --------------
});
//table
const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
/**
* 新增事件
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑事件
*/
async function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 详情
*/
async function handleDetail(record) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteDict({ id: record.id }, reload);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDeleteDict({ ids: selectedRowKeys.value }, () => {
// update-begin--author:liaozhiyang---date:20240701---forTV360X-1665
reload();
selectedRowKeys.value = [];
selectedRows.value = [];
// update-end--author:liaozhiyang---date:20240701---forTV360X-1665
});
}
/**
* 成功回调
*/
function handleSuccess({ isUpdate, values }) {
if (isUpdate) {
updateTableDataRecord(values.id, values);
} else {
reload();
}
}
/**
* 刷新缓存
*/
async function handlerRefreshCache() {
const result = await refreshCache();
if (result.success) {
const res = await queryAllDictItems();
removeAuthCache(DB_DICT_DATA_KEY);
// update-begin--author:liaozhiyang---date:20230908---forQQYUN-6417
const userStore = useUserStore();
userStore.setAllDictItems(res.result);
// update-end--author:liaozhiyang---date:20230908---forQQYUN-6417
createMessage.success('刷新缓存完成!');
} else {
createMessage.error('刷新缓存失败!');
}
}
/**
* 字典配置
*/
function handleItem(record) {
openDrawer(true, {
id: record.id,
});
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '字典配置',
onClick: handleItem.bind(null, record),
},
{
label: '删除',
popConfirm: {
title: '确定删除吗?',
confirm: handleDelete.bind(null, record),
},
},
];
}
</script>
<style scoped></style>

View File

@ -1,72 +0,0 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/dictType/dictType/list',
save='/dictType/dictType/add',
edit='/dictType/dictType/edit',
deleteOne = '/dictType/dictType/delete',
deleteBatch = '/dictType/dictType/deleteBatch',
importExcel = '/dictType/dictType/importExcel',
exportXls = '/dictType/dictType/exportXls',
}
/**
* 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 });
}

View File

@ -1,43 +0,0 @@
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: 'dictName'
},
{
title: '字典编码',
align: "center",
dataIndex: 'dictCode'
},
{
title: '描述',
align: "center",
dataIndex: 'description'
},
{
title: '创建时间',
align: "center",
sorter: true,
dataIndex: 'createTime'
},
{
title: '更新时间',
align: "center",
dataIndex: 'updateTime'
},
];
// 高级查询数据
export const superQuerySchema = {
dictName: {title: '字典名称',order: 0,view: 'text', type: 'string',},
dictCode: {title: '字典编码',order: 1,view: 'text', type: 'string',},
description: {title: '描述',order: 2,view: 'textarea', type: 'string',},
createTime: {title: '创建时间',order: 3,view: 'datetime', type: 'string',},
updateTime: {title: '更新时间',order: 4,view: 'datetime', type: 'string',},
};

View File

@ -1,72 +0,0 @@
import { defHttp } from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/dictType/dictTypeItem/list',
save='/dictType/dictTypeItem/add',
edit='/dictType/dictTypeItem/edit',
deleteOne = '/dictType/dictTypeItem/delete',
deleteBatch = '/dictType/dictTypeItem/deleteBatch',
importExcel = '/dictType/dictTypeItem/importExcel',
exportXls = '/dictType/dictTypeItem/exportXls',
}
/**
* 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 });
}

View File

@ -1,45 +0,0 @@
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: 'itemText'
},
{
title: '字典项值',
align: "center",
dataIndex: 'itemValue'
},
{
title: '描述',
align: "center",
dataIndex: 'description'
},
{
title: '排序',
align: "center",
dataIndex: 'sortOrder'
},
{
title: '状态',
align: "center",
dataIndex: 'status_dictText'
},
];
// 高级查询数据
export const superQuerySchema = {
dictId: {title: '字典id',order: 0,view: 'text', type: 'string',},
itemText: {title: '字典项文本',order: 1,view: 'text', type: 'string',},
itemValue: {title: '字典项值',order: 2,view: 'text', type: 'string',},
description: {title: '描述',order: 3,view: 'text', type: 'string',},
sortOrder: {title: '排序',order: 4,view: 'number', type: 'number',},
status: {title: '状态1启用 0不启用',order: 5,view: 'number', type: 'number',},
createTime: {title: '创建时间',order: 6,view: 'datetime', type: 'string',},
updateTime: {title: '更新时间',order: 7,view: 'datetime', type: 'string',},
};

View File

@ -1,249 +0,0 @@
<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-row>
</a-form>
</div> -->
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<!-- <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> -->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<!-- <super-query :config="superQueryConfig" @search="handleSuperQuery" /> -->
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
</template>
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<DictTypeItemModal ref="registerModal" @success="handleSuccess" :dictId="dictId"></DictTypeItemModal>
</div>
</template>
<script lang="ts" name="dictType-dictTypeItem" setup>
import { ref, reactive, onMounted } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, superQuerySchema } from './DictTypeItem.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './DictTypeItem.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import DictTypeItemModal from './components/DictTypeItemModal.vue'
import { useUserStore } from '/@/store/modules/user';
const props = defineProps({
dictId: { type: String, default: () => ({}) },
});
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: 'dict_type_item',
api: list,
columns,
canResize: false,
useSearchForm: false,
actionColumn: {
width: 120,
fixed: 'right',
},
beforeFetch: async (params) => {
params.column = 'sortOrder'
params.order = 'asc'
params.dictId = props.dictId
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "dict_type_item",
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: handleEdit.bind(null, record)
},
];
}
/**
* 下拉操作栏
*/
function getDropDownAction(record) {
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
}
}
]
}
/**
* 查询
*/
function searchQuery() {
reload();
}
/**
* 重置
*/
function searchReset() {
formRef.value.resetFields();
selectedRowKeys.value = [];
//
reload();
}
onMounted(() => {
//
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

@ -1,283 +0,0 @@
<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="dictName">
<template #label><span title="字典名称">字典名称</span></template>
<JInput v-model:value="queryParam.dictName" />
</a-form-item>
</a-col>
<a-col :lg="6">
<a-form-item name="dictCode">
<template #label><span title="字典编码">字典编码</span></template>
<JInput v-model:value="queryParam.dictCode" />
</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 @click="toggleSearchStatus = !toggleSearchStatus" style="margin-left: 8px">
{{ toggleSearchStatus ? '收起' : '展开' }}
<Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
</a> -->
</a-col>
</span>
</a-col>
</a-row>
</a-form>
</div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'dictType:dict_type:add'" @click="handleAdd"
preIcon="ant-design:plus-outlined"> 新增</a-button>
<!-- <a-button type="primary" v-auth="'dictType:dict_type:exportXls'" preIcon="ant-design:export-outlined"
@click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" v-auth="'dictType:dict_type:importExcel'" preIcon="ant-design:import-outlined"
@click="onImportXls">导入</j-upload-button> -->
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button v-auth="'dictType:dict_type:deleteBatch'">批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<!-- <super-query :config="superQueryConfig" @search="handleSuperQuery" /> -->
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<DictTypeModal ref="registerModal" @success="handleSuccess"></DictTypeModal>
</div>
<a-drawer title="字典项" width="60vw" :open="itemOpen" @close="onItemClose">
<template #footer>
<a-button type="primary" @click="onItemClose" style="float: right;">关闭</a-button>
</template>
<DictTypeItemList v-if="itemOpen" :dictId="dictId"></DictTypeItemList>
</a-drawer>
</template>
<script lang="ts" name="dictType-dictType" setup>
import { ref, reactive } from 'vue';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
import { columns, superQuerySchema } from './DictType.data';
import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './DictType.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import DictTypeModal from './components/DictTypeModal.vue'
import { useUserStore } from '/@/store/modules/user';
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
import DictTypeItemList from './DictTypeItemList.vue';
const formRef = ref();
const queryParam = reactive<any>({});
const toggleSearchStatus = ref<boolean>(false);
const registerModal = ref();
const userStore = useUserStore();
const itemOpen = ref(false)
const dictId = ref(null)
//table
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
tableProps: {
title: 'dict_type',
api: list,
columns,
canResize: false,
useSearchForm: false,
actionColumn: {
width: 200,
fixed: 'right',
},
beforeFetch: async (params) => {
return Object.assign(params, queryParam);
},
},
exportConfig: {
name: "dict_type",
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);
}
/**
* 删除事件
*/
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 handleItem(record) {
dictId.value = record.id
itemOpen.value = true
}
/**
* 关闭字典配置抽屉
*/
function onItemClose(){
dictId.value = null
itemOpen.value = false
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'dictType:dict_type:edit'
},
{
label: '字典配置',
onClick: handleItem.bind(null, record)
}, {
label: '删除',
popConfirm: {
title: '是否确认删除:' + record.dictName,
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
},
auth: 'dictType:dict_type:delete'
}
];
}
/**
* 查询
*/
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

@ -1,171 +0,0 @@
<template>
<a-spin :spinning="confirmLoading">
<JFormContainer :disabled="disabled">
<template #detail>
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol" name="DictTypeForm">
<a-row>
<a-col :span="24">
<a-form-item label="字典名称" v-bind="validateInfos.dictName" id="DictTypeForm-dictName" name="dictName">
<a-input v-model:value="formData.dictName" placeholder="请输入字典名称" allow-clear ></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="字典编码" v-bind="validateInfos.dictCode" id="DictTypeForm-dictCode" name="dictCode">
<a-input v-model:value="formData.dictCode" placeholder="请输入字典编码" :readonly="!!formData.id" allow-clear ></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="描述" v-bind="validateInfos.description" id="DictTypeForm-description" name="description">
<a-textarea v-model:value="formData.description" :rows="4" placeholder="请输入描述" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="创建时间" v-bind="validateInfos.createTime" id="DictTypeForm-createTime" name="createTime">
<a-date-picker placeholder="请选择创建时间" v-model:value="formData.createTime" showTime value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" disabled allow-clear />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="更新时间" v-bind="validateInfos.updateTime" id="DictTypeForm-updateTime" name="updateTime">
<a-date-picker placeholder="请选择更新时间" v-model:value="formData.updateTime" showTime value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" disabled allow-clear />
</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 '../DictType.api';
import { Form } from 'ant-design-vue';
import JFormContainer from '/@/components/Form/src/container/JFormContainer.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: '',
dictName: '',
dictCode: '',
description: '',
createTime: '',
updateTime: '',
});
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({
dictName: [{ required: true, message: '请输入字典名称!'},],
dictCode: [{ 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

@ -1,196 +0,0 @@
<template>
<a-spin :spinning="confirmLoading">
<JFormContainer :disabled="disabled">
<template #detail>
<a-form ref="formRef" class="antd-modal-form" :labelCol="labelCol" :wrapperCol="wrapperCol"
name="DictTypeItemForm">
<a-row>
<a-col :span="24">
<a-form-item label="字典项名称" v-bind="validateInfos.itemText" id="DictTypeItemForm-itemText" name="itemText">
<a-input v-model:value="formData.itemText" placeholder="请输入字典项文本" allow-clear></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="字典项值" v-bind="validateInfos.itemValue" id="DictTypeItemForm-itemValue"
name="itemValue">
<a-input v-model:value="formData.itemValue" placeholder="请输入字典项值" allow-clear></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="描述" v-bind="validateInfos.description" id="DictTypeItemForm-description"
name="description">
<a-input v-model:value="formData.description" placeholder="请输入描述" allow-clear></a-input>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="排序" v-bind="validateInfos.sortOrder" id="DictTypeItemForm-sortOrder" name="sortOrder">
<a-input-number v-model:value="formData.sortOrder" placeholder="请输入排序" style="width: 100%" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="状态" v-bind="validateInfos.status" id="DictTypeItemForm-status" name="status">
<j-dict-select-tag type='radio' v-model:value="formData.status" dictCode="iz_enabled"
placeholder="请选择状态" />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="创建时间" v-bind="validateInfos.createTime" id="DictTypeItemForm-createTime"
name="createTime">
<a-date-picker placeholder="请选择创建时间" v-model:value="formData.createTime" showTime
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" disabled allow-clear />
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item label="更新时间" v-bind="validateInfos.updateTime" id="DictTypeItemForm-updateTime"
name="updateTime">
<a-date-picker placeholder="请选择更新时间" v-model:value="formData.updateTime" showTime
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" disabled allow-clear />
</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 '../DictTypeItem.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';
const props = defineProps({
formDisabled: { type: Boolean, default: false },
formData: { type: Object, default: () => ({}) },
formBpm: { type: Boolean, default: true },
dictId: { type: Object, default: () => ({}) },
});
const formRef = ref();
const useForm = Form.useForm;
const emit = defineEmits(['register', 'ok']);
const formData = reactive<Record<string, any>>({
id: '',
dictId: '',
itemText: '',
itemValue: '',
description: '',
sortOrder: undefined,
status: '0',
createTime: '',
updateTime: '',
});
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({
itemText: [{ required: true, message: '请输入字典项文本!' },],
itemValue: [{ required: true, message: '请输入字典项值!' },],
sortOrder: [{ 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);
}
formData.dictId = props.dictId
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

@ -1,80 +0,0 @@
<template>
<j-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<DictTypeItemForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false" :dictId="dictId"></DictTypeItemForm>
</j-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import DictTypeItemForm from './DictTypeItemForm.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']);
const props = defineProps({
dictId:{ type: Object, default: () => ({})},
});
/**
* 新增
*/
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

@ -1,77 +0,0 @@
<template>
<j-modal :title="title" :width="width" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<DictTypeForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></DictTypeForm>
</j-modal>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue';
import DictTypeForm from './DictTypeForm.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

@ -25,20 +25,51 @@
</a-form> </a-form>
</div> </div>
<a-row> <a-row>
<a-col :span="8" v-for="directive of tableData.records" :key="directive.id"> <a-col :span="6" v-for="directive of tableData.records" :key="directive.id">
<a-card :title="directive.packageName" :bordered="false" style="margin: 5px;"> <a-card :bordered="false" style="margin: 5px;">
<div>{{ directive.description }}</div> <!-- 自定义标题区域 -->
<div>{{ directive.createTime }} - {{ directive.createBy }}</div> <template #title>
<template #actions> <div style="display: flex; align-items: center; justify-content: space-between;">
<a-button type="link" @click="packageEdit(directive)" preIcon="tabler:settings"></a-button> <span>{{ directive.packageName }}</span>
<a-popconfirm title="是否确认删除?" ok-text="确认" cancel-text="取消" @confirm="remove(directive)"> <a-dropdown :trigger="['hover']" placement="bottomRight">
<a-button type="link" danger preIcon="ant-design:delete-twotone"></a-button> <a-button type="link" preIcon="tabler:settings"></a-button>
</a-popconfirm> <template #overlay>
<a-menu>
<a-menu-item @click="packageEdit(directive)">
<template #icon></template>
编辑
</a-menu-item>
<a-menu-item>
<a-popconfirm title="是否确认删除?" ok-text="确认" cancel-text="取消" @confirm="remove(directive)">
删除
</a-popconfirm>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</template> </template>
<!-- 保持原有内容区域 -->
<div style="position: relative; height: 23vh;">
<div
style="height: 80%; overflow-y: auto; line-height: 1.5;white-space: pre-line;word-wrap: break-word;overflow-wrap: break-word;">
{{ directive.description }}
</div>
<div
style="position: absolute;bottom: 0;right: 0;font-weight: 600;color: rgba(0, 0, 0, 0.6);padding: 8px 0 0;">
{{ directive.createTime }} - {{ directive.createBy_dictText }}
</div>
</div>
</a-card> </a-card>
</a-col> </a-col>
</a-row> </a-row>
<div
style="position: fixed;right: 20px;bottom: 20px;z-index: 999;padding: 8px 16px;border-radius: 4px;display: flex;align-items: center;">
<span style="margin-right: 10px;"> {{ tableData.total }} 条数据</span>
<Pagination showLessItems v-model:current="pageParams.pageNo" :pageSize="pageParams.pageSize" size="small"
show-quick-jumper :total="tableData.total" @change="queryList" />
</div>
</div> </div>
<!-- 表单区域 --> <!-- 表单区域 -->
<DirectivePackageModal ref="registerModal" @success="handleSuccess"></DirectivePackageModal> <DirectivePackageModal ref="registerModal" @success="handleSuccess"></DirectivePackageModal>
@ -48,6 +79,7 @@
import { ref, reactive, onMounted } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import DirectivePackageModal from './components/DirectivePackageModal.vue' import DirectivePackageModal from './components/DirectivePackageModal.vue'
import { list, queryById, deleteOne } from './DirectivePackage.api' import { list, queryById, deleteOne } from './DirectivePackage.api'
import { Pagination } from 'ant-design-vue';
const registerModal = ref(); const registerModal = ref();
const searchForm = ref({}) const searchForm = ref({})
@ -64,6 +96,7 @@ const wrapperCol = reactive({
xl: 14, xl: 14,
xxl: 14 xxl: 14
}); });
const pageParams = ref({ pageNo: 1, pageSize: 8 })
/** /**
* 搜索 * 搜索
@ -97,8 +130,9 @@ function handleSuccess() {
/** /**
* 数据查询 * 数据查询
*/ */
function queryList(params) { function queryList() {
list({ pageNo: 1, pageSize: 10, packageName: searchForm.value.packageName }).then(res => { list({ pageNo: pageParams.value.pageNo, pageSize: pageParams.value.pageSize, packageName: searchForm.value.packageName }).then(res => {
console.log("🌊 ~ list ~ res:", res)
tableData.value = res tableData.value = res
}) })
} }

View File

@ -11,10 +11,17 @@
<a-input v-model:value="formData.packageName" placeholder="请输入服务指令包名称" allow-clear></a-input> <a-input v-model:value="formData.packageName" placeholder="请输入服务指令包名称" allow-clear></a-input>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24">
<a-form-item label="是否启用" v-bind="validateInfos.izEnabled" id="DirectivePackageForm-izEnabled"
name="izEnabled">
<j-dict-select-tag type='radio' v-model:value="formData.izEnabled" dictCode="iz_enabled"
placeholder="是否启用" allow-clear />
</a-form-item>
</a-col>
<a-col :span="24"> <a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.description" id="DirectivePackageForm-description" <a-form-item label="备注" v-bind="validateInfos.description" id="DirectivePackageForm-description"
name="description"> name="description">
<a-textarea v-model:value="formData.description" :rows="4" placeholder="请输入备注" /> <a-textarea v-model:value="formData.description" :rows="16" placeholder="请输入备注" />
</a-form-item> </a-form-item>
</a-col> </a-col>
<!-- <a-col :span="24"> <!-- <a-col :span="24">
@ -22,13 +29,6 @@
<a-input-number v-model:value="formData.sort" placeholder="请输入排序" style="width: 100%" /> <a-input-number v-model:value="formData.sort" placeholder="请输入排序" style="width: 100%" />
</a-form-item> </a-form-item>
</a-col> --> </a-col> -->
<a-col :span="24">
<a-form-item label="是否启用" v-bind="validateInfos.izEnabled" id="DirectivePackageForm-izEnabled"
name="izEnabled">
<j-dict-select-tag type='radio' v-model:value="formData.izEnabled" dictCode="iz_enabled"
placeholder="是否启用" allow-clear />
</a-form-item>
</a-col>
</a-row> </a-row>
</a-form> </a-form>
</template> </template>

View File

@ -2,43 +2,48 @@
<!-- <j-modal :title="title" :width="width" :maskClosable="false" :fullscreen="true" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭"> <!-- <j-modal :title="title" :width="width" :maskClosable="false" :fullscreen="true" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<DirectivePackageForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></DirectivePackageForm> <DirectivePackageForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></DirectivePackageForm>
</j-modal> --> </j-modal> -->
<a-drawer v-model:open="visible" v-if="visible" :title="title" width="90vw" :closable="false" <a-drawer v-model:open="visible" v-if="visible" :title="title" width="80vw" :closable="false"
:footer-style="{ textAlign: 'right' }" @close="handleCancel"> :footer-style="{ textAlign: 'right' }" @close="handleCancel">
<div style="display:flex;justify-content:space-between"> <div style="display:flex;justify-content:space-between">
<div> <div>
<a-card title="服务指令包详情" style="width: 27vw"> <a-card title="服务指令包详情" style="width: 25vw">
<DirectivePackageForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"> <DirectivePackageForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false">
</DirectivePackageForm> </DirectivePackageForm>
</a-card> </a-card>
</div> </div>
<a-card title="服务指令" style="width: 27vw"> <a-card title="服务指令" style="width: 25vw">
<template #extra> <template #extra>
<a href="#" @click="handleQuoteDirectives">引用 </a> <a href="javascript:void(0);" @click="handleQuoteDirectives">引用 </a>
<a href="#" @click="handleAddDirectives">新增</a> <a href="javascript:void(0);" @click="handleAddDirectives">新增</a>
</template> </template>
<div class="scrollable-content"> <div class="scrollable-content">
<a-row> <a-row>
<a-col :span="11" v-for="directive of seletedRecord.directives" :key="directive.id" style="margin: 5px;" <a-col :span="22" :push="1" v-for="directive of seletedRecord.directives" :key="directive.id"
@click="directiveInfo(directive)"> style="margin-top: 15px;" @click="directiveInfo(directive)">
<a-card> <a-badge-ribbon :text="filterDictTextByCache('period_type', directive.cycleType)"
<span :class="{ 'selected': selectedDirective === directive.id }"> :style="{ top: '-10px' }">
{{ directive.directiveName + handleTags('', directive, '') }} <a-card size="small">
</span> <span>
<template #actions> <a-popconfirm title="是否确认移除?" ok-text="确认" cancel-text="取消"
<a-popconfirm title="是否确认移除?" ok-text="确认" cancel-text="取消" @confirm="deleteDirective(directive.id)"> @confirm="deleteDirective(directive.id)">
<a-button type="link" danger preIcon="ic:baseline-remove-circle"></a-button> <a-button type="link" danger preIcon="ic:baseline-remove-circle"></a-button>
</a-popconfirm> </a-popconfirm>
</template> </span>
</a-card> <span :class="{ 'selected': selectedDirective === directive.id }">
{{ directive.directiveName + handleTags('', directive, '') }}
</span>
</a-card>
</a-badge-ribbon>
</a-col> </a-col>
</a-row> </a-row>
</div> </div>
</a-card> </a-card>
<div> <div>
<a-card title="服务指令详情" style="width: 27vw"> <a-card title="服务指令详情" style="width: 25vw">
<div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div> <div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div>
<div class="directiveInfoClass">服务类别{{ derectiveInfo.categoryName }}</div> <div class="directiveInfoClass">服务类别{{ derectiveInfo.categoryName || derectiveInfo.categoryId_dictText }}
<div class="directiveInfoClass">服务类型{{ derectiveInfo.typeName }}</div> </div>
<div class="directiveInfoClass">服务类型{{ derectiveInfo.typeName || derectiveInfo.typeId_dictText }}</div>
<div class="directiveInfoClass">服务指令名称{{ derectiveInfo.directiveName }}</div> <div class="directiveInfoClass">服务指令名称{{ derectiveInfo.directiveName }}</div>
<div class="directiveInfoClass">周期类型{{ filterDictTextByCache('period_type', derectiveInfo.cycleType) }}</div> <div class="directiveInfoClass">周期类型{{ filterDictTextByCache('period_type', derectiveInfo.cycleType) }}</div>
<div class="directiveInfoClass">服务时长(分钟){{ derectiveInfo.serviceDuration }}</div> <div class="directiveInfoClass">服务时长(分钟){{ derectiveInfo.serviceDuration }}</div>
@ -288,5 +293,4 @@ defineExpose({
padding-right: 8px; padding-right: 8px;
/* 防止滚动条遮挡内容 */ /* 防止滚动条遮挡内容 */
} }
</style> </style>

View File

@ -1,18 +1,18 @@
<template> <template>
<div class="p-2"> <div class="p-2">
<a-row> <a-row>
<a-col :span="10"> <a-col :span="9">
<!--查询区域--> <!--查询区域-->
<div class="jeecg-basic-table-form-container"> <div class="jeecg-basic-table-form-container">
<a-form ref="formRef" :model="searchForm" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form ref="formRef" :model="searchForm" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :lg="10"> <a-col :span="14">
<a-form-item name="packageName"> <a-form-item name="packageName">
<template #label><span title="服务指令包名称">服务指令包</span></template> <template #label><span title="服务指令包名称">服务指令包</span></template>
<a-input v-model:value="searchForm.packageName" allow-clear /> <a-input v-model:value="searchForm.packageName" allow-clear />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :xl="5" :lg="6" :md="9" :sm="24"> <a-col :span="10">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons"> <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="9"> <a-col :lg="9">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button> <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
@ -24,47 +24,48 @@
</a-row> </a-row>
</a-form> </a-form>
</div> </div>
<div style="background-color: #000;padding: 20px;"> <div>
<a-card :title="directive.packageName" :key="directive.id" :bordered="false" <div class="scrollable-content">
style="width: 300px;margin: 10px;" v-for="directive of tableData.records" <a-row>
:class="{ 'selected': selectedDirective.id === directive.id }" @click="handlePackageClick(directive)"> <a-col :span="11" :push="1" v-for="(directive, index) of tableData.records" :key="directive.id">
<div>{{ directive.description }}</div> <!-- <a-popover :placement="index % 2 == 0 ? 'left' : 'right'">
<div>{{ directive.createTime }} - {{ directive.createBy }}</div> <template #content>
</a-card> <p style="width: 10vw; word-wrap: break-word; white-space: pre-wrap">{{ directive.description ||
'暂无说明' }}</p>
</template> -->
<a-card :bordered="false" size="small" class="smart-card"
style="margin: 10px;box-shadow: 1px 1px 5px #b0b0b0;" @click="handlePackageClick(directive)"
:class="{ 'selected': selectedDirective.id === directive.id }">
<div class="selected-indicator" v-if="selectedDirective.id === directive.id"></div>
<div>{{ directive.packageName }}</div>
<div> {{ directive.createBy }}</div>
<div>{{ directive.createTime }}</div>
</a-card>
<!-- </a-popover> -->
</a-col>
</a-row>
</div>
</div> </div>
</a-col> </a-col>
<a-col :span="8"> <a-col :span="8">
<div> <a-card title="服务指令" style="width: 100%">
<a-card title="服务指令" style="width: 100%"> <div class="scrollable-content">
<div v-for="derectiveInfo of selectedDirective.directives" :key="derectiveInfo.id" <a-row>
class="derectiveInfoClass" @click="directiveInfo(derectiveInfo)" <a-col :span="22" :push="1" v-for="directive of selectedDirective.directives" :key="directive.id"
:class="{ 'selected': directiveId === derectiveInfo.id }"> style="margin-top: 15px;" @click="directiveInfo(directive)">
<div class="">分类标签{{ derectiveInfo.instructionTagId_dictText }}</div> <a-badge-ribbon :text="filterDictTextByCache('period_type', directive.cycleType)" :style="{ top: '-10px' }">
<div class="directiveInfoClass">服务类别{{ derectiveInfo.categoryName }}</div> <a-card size="small">
<div class="directiveInfoClass">服务类型{{ derectiveInfo.typeName }}</div> <span :class="{ 'selected-dire': directiveId === directive.id }">
<div class="directiveInfoClass">服务指令名称{{ derectiveInfo.directiveName }}</div> {{ directive.directiveName + handleTags('', directive, '') }}
<div class="directiveInfoClass">周期类型{{ filterDictTextByCache('period_type', derectiveInfo.cycleType) }} </span>
</div> </a-card>
<div class="directiveInfoClass">服务时长(分钟){{ derectiveInfo.serviceDuration }}</div> </a-badge-ribbon>
<div class="directiveInfoClass">服务说明{{ derectiveInfo.serviceContent }}</div> </a-col>
<div class="directiveInfoClass">指令标签{{ handleTags('', derectiveInfo, '') }}</div> </a-row>
<div class="directiveInfoClass">语音文件 </div>
<span v-if="!derectiveInfo.mp3File">暂无文件</span> </a-card>
<audio controls disabled="false" v-else>
<source :src="getFileAccessHttpUrl(derectiveInfo.mp3File)">
</audio>
</div>
<div class="directiveInfoClass">视频文件
<span v-if="!derectiveInfo.mp4File">暂无文件</span>
<video controls v-else>
<source :src="getFileAccessHttpUrl(derectiveInfo.mp4File)">
</video>
</div>
</div>
</a-card>
</div>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6" style="margin-left: 1vw;">
<div> <div>
<a-card title="服务指令详情" style="width: 100%"> <a-card title="服务指令详情" style="width: 100%">
<div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div> <div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div>
@ -109,8 +110,8 @@ const derectiveInfo = ref({})
const labelCol = reactive({ const labelCol = reactive({
xs: 24, xs: 24,
sm: 4, sm: 4,
xl: 16, xl: 9,
xxl: 16 xxl: 9
}); });
const wrapperCol = reactive({ const wrapperCol = reactive({
xs: 24, xs: 24,
@ -153,7 +154,7 @@ function handleSuccess() {
*/ */
function queryList(params) { function queryList(params) {
resetSeletedDirectiveInfo() resetSeletedDirectiveInfo()
list({ pageNo: 1, pageSize: 10, packageName: searchForm.value.packageName }).then(res => { list({ pageNo: 1, pageSize: -1, packageName: searchForm.value.packageName }).then(res => {
tableData.value = res tableData.value = res
selectedDirective.value = { id: '' } selectedDirective.value = { id: '' }
}) })
@ -220,7 +221,7 @@ function resetSeletedDirectiveInfo() {
} }
onMounted(() => { onMounted(() => {
queryList({ pageNo: 1, pageSize: 10 }) queryList({ pageNo: 1, pageSize: -1 })
}) })
defineExpose({ defineExpose({
@ -260,11 +261,62 @@ defineExpose({
} }
.selected { .selected {
background-color: lightgreen; background: url("@/assets/icons/success.svg") no-repeat;
background-position: calc(100% - 5px) calc(100% - 5px);
background-size: auto 60%;
transition: none !important;
}
.selected-dire {
color: rgb(0, 156, 0);
font-weight: bold;
} }
.derectiveInfoClass { .derectiveInfoClass {
border: 1px solid grey; border: 1px solid grey;
margin: 5px; margin: 5px;
} }
.smart-card {
margin: 10px;
position: relative;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
//
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}
//
&:active {
transform: scale(0.98);
}
//
&.active-card {
border-left: 4px solid #1890ff;
.selected-indicator {
position: absolute;
right: 8px;
top: 8px;
width: 8px;
height: 8px;
background: #1890ff;
border-radius: 50%;
}
}
}
.scrollable-content {
height: 70vh;
/* 设置固定高度为视口的50% */
overflow-y: auto;
/* 垂直方向超出时显示滚动条 */
padding-right: 8px;
/* 防止滚动条遮挡内容 */
}
</style> </style>

View File

@ -61,13 +61,13 @@
dictCode="institutional_discount" allowClear /> dictCode="institutional_discount" allowClear />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="12"> <!-- <a-col :span="12">
<a-form-item label="收费频次" v-bind="validateInfos.chargingFrequency" <a-form-item label="收费频次" v-bind="validateInfos.chargingFrequency"
id="ConfigServiceDirectiveForm-chargingFrequency" name="chargingFrequency"> id="ConfigServiceDirectiveForm-chargingFrequency" name="chargingFrequency">
<j-dict-select-tag type="list" v-model:value="formData.chargingFrequency" dictCode="billing_frequency" <j-dict-select-tag type="list" v-model:value="formData.chargingFrequency" dictCode="billing_frequency"
placeholder="请选择收费频次" allowClear /> placeholder="请选择收费频次" allowClear />
</a-form-item> </a-form-item>
</a-col> </a-col> -->
<a-col :span="12"> <a-col :span="12">
<a-form-item label="周期类型" v-bind="validateInfos.cycleType" id="ConfigServiceDirectiveForm-cycleType" <a-form-item label="周期类型" v-bind="validateInfos.cycleType" id="ConfigServiceDirectiveForm-cycleType"
name="cycleType"> name="cycleType">

View File

@ -1,5 +1,4 @@
import {BasicColumn} from '/@/components/Table'; import {BasicColumn} from '/@/components/Table';
//列表数据 //列表数据
export const columns: BasicColumn[] = [ export const columns: BasicColumn[] = [
{ {

View File

@ -24,18 +24,51 @@
</a-row> </a-row>
</a-form> </a-form>
</div> </div>
<div style="background-color: #000;padding: 20px;"> <a-row>
<a-card :title="directive.tagName" :key="directive.id" :bordered="false" style="width: 300px;margin: 10px;" <a-col :span="6" v-for="directive of tableData.records" :key="directive.id">
v-for="directive of tableData.records"> <a-card :bordered="false" style="margin: 5px;">
<div>{{ directive.description }}</div> <!-- 自定义标题区域 -->
<div>{{ directive.createTime }} - {{ directive.createBy }}</div> <template #title>
<div> <div style="display: flex; align-items: center; justify-content: space-between;">
<a type="primary" @click="serviceTagEdit(directive)" style="margin-right: 8px">编辑</a> <span>{{ directive.tagName }}</span>
<a-popconfirm title="是否确认删除?" ok-text="确认" cancel-text="取消" @confirm="remove(directive)"> <a-dropdown :trigger="['hover']" placement="bottomRight">
<a href="#">删除</a> <a-button type="link" preIcon="tabler:settings"></a-button>
</a-popconfirm> <template #overlay>
</div> <a-menu>
</a-card> <a-menu-item @click="tagEdit(directive)">
<template #icon></template>
编辑
</a-menu-item>
<a-menu-item>
<a-popconfirm title="是否确认删除?" ok-text="确认" cancel-text="取消" @confirm="remove(directive)">
删除
</a-popconfirm>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</template>
<!-- 保持原有内容区域 -->
<div style="position: relative; height: 11vh;">
<div
style="height: 75%; overflow-y: auto; line-height: 1.5;white-space: pre-line;word-wrap: break-word;overflow-wrap: break-word;">
{{ directive.description }}
</div>
<div
style="position: absolute;bottom: 0;right: 0;font-weight: 600;color: rgba(0, 0, 0, 0.6);padding: 8px 0 0;">
{{ directive.createTime }} - {{ directive.createBy_dictText }}
</div>
</div>
</a-card>
</a-col>
</a-row>
<div
style="position: fixed;right: 20px;bottom: 20px;z-index: 999;padding: 8px 16px;border-radius: 4px;display: flex;align-items: center;">
<span style="margin-right: 10px;"> {{ tableData.total }} 条数据</span>
<Pagination showLessItems v-model:current="pageParams.pageNo" :pageSize="pageParams.pageSize" size="small"
show-quick-jumper :total="tableData.total" @change="queryList" />
</div> </div>
</div> </div>
<!-- 表单区域 --> <!-- 表单区域 -->
@ -46,6 +79,7 @@
import { ref, reactive, onMounted } from 'vue'; import { ref, reactive, onMounted } from 'vue';
import ServiceTagModal from './components/ServiceTagModal.vue' import ServiceTagModal from './components/ServiceTagModal.vue'
import { list, queryById, deleteOne } from './ServiceTag.api' import { list, queryById, deleteOne } from './ServiceTag.api'
import { Pagination } from 'ant-design-vue';
const registerModal = ref(); const registerModal = ref();
const searchForm = ref({}) const searchForm = ref({})
@ -62,6 +96,7 @@ const wrapperCol = reactive({
xl: 14, xl: 14,
xxl: 14 xxl: 14
}); });
const pageParams = ref({ pageNo: 1, pageSize: 12 })
/** /**
* 搜索 * 搜索
@ -95,8 +130,9 @@ function handleSuccess() {
/** /**
* 数据查询 * 数据查询
*/ */
function queryList(params) { function queryList() {
list({ pageNo: 1, pageSize: 10, tagName: searchForm.value.tagName }).then(res => { list({ pageNo: pageParams.value.pageNo, pageSize: pageParams.value.pageSize, tagName: searchForm.value.tagName }).then(res => {
console.log("🌊 ~ list ~ res:", res)
tableData.value = res tableData.value = res
}) })
} }
@ -105,7 +141,7 @@ function queryList(params) {
* 编辑 * 编辑
* @param data * @param data
*/ */
function serviceTagEdit(data) { function tagEdit(data) {
queryById({ id: data.id }).then(item => { queryById({ id: data.id }).then(item => {
registerModal.value.edit(item); registerModal.value.edit(item);
}) })

View File

@ -2,14 +2,14 @@
<j-modal :title="title" width="70vw" :visible="visible" @ok="handleOk" <j-modal :title="title" width="70vw" :visible="visible" @ok="handleOk"
:okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭"
:maskClosable="false"> :maskClosable="false">
<ServiceTagForm ref="registerForm" v-if="visible" @ok="submitCallback" :formDisabled="disableSubmit" <ConfigServiceDirectiveForm ref="registerForm" v-if="visible" @ok="submitCallback" :formDisabled="disableSubmit"
:formBpm="false"></ServiceTagForm> :formBpm="false"></ConfigServiceDirectiveForm>
</j-modal> </j-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, nextTick, defineExpose } from 'vue'; import { ref, nextTick, defineExpose } from 'vue';
import ServiceTagForm from './ServiceTagForm.vue' import ConfigServiceDirectiveForm from './ConfigServiceDirectiveForm.vue'
import JModal from '/@/components/Modal/src/JModal/JModal.vue'; import JModal from '/@/components/Modal/src/JModal/JModal.vue';
import { array } from 'vue-types'; import { array } from 'vue-types';

View File

@ -3,32 +3,32 @@
<JFormContainer :disabled="disabled"> <JFormContainer :disabled="disabled">
<template #detail> <template #detail>
<a-form ref="formRef" class="antd-modal-form" layout="vertical" :labelCol="labelCol" :wrapperCol="wrapperCol" <a-form ref="formRef" class="antd-modal-form" layout="vertical" :labelCol="labelCol" :wrapperCol="wrapperCol"
name="ServiceTagForm"> name="DirectiveTagForm">
<a-row> <a-row>
<a-col :span="24"> <a-col :span="24">
<a-form-item label="服务标签名称" v-bind="validateInfos.tagName" id="ServiceTagForm-tagName" <a-form-item label="服务标签名称" v-bind="validateInfos.tagName" id="DirectiveTagForm-tagName"
name="tagName"> name="tagName">
<a-input v-model:value="formData.tagName" placeholder="请输入服务标签名称" allow-clear></a-input> <a-input v-model:value="formData.tagName" placeholder="请输入服务标签名称" allow-clear></a-input>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24"> <a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.description" id="ServiceTagForm-description" <a-form-item label="是否启用" v-bind="validateInfos.izEnabled" id="DirectiveTagForm-izEnabled"
name="description">
<a-textarea v-model:value="formData.description" :rows="4" placeholder="请输入备注" />
</a-form-item>
</a-col>
<!-- <a-col :span="24">
<a-form-item label="排序" v-bind="validateInfos.sort" id="ServiceTagForm-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="ServiceTagForm-izEnabled"
name="izEnabled"> name="izEnabled">
<j-dict-select-tag type='radio' v-model:value="formData.izEnabled" dictCode="iz_enabled" <j-dict-select-tag type='radio' v-model:value="formData.izEnabled" dictCode="iz_enabled"
placeholder="是否启用" allow-clear /> placeholder="是否启用" allow-clear />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :span="24">
<a-form-item label="备注" v-bind="validateInfos.description" id="DirectiveTagForm-description"
name="description">
<a-textarea v-model:value="formData.description" :rows="16" placeholder="请输入备注" />
</a-form-item>
</a-col>
<!-- <a-col :span="24">
<a-form-item label="排序" v-bind="validateInfos.sort" id="DirectiveTagForm-sort" name="sort">
<a-input-number v-model:value="formData.sort" placeholder="请输入排序" style="width: 100%" />
</a-form-item>
</a-col> -->
</a-row> </a-row>
</a-form> </a-form>
</template> </template>

View File

@ -1,18 +1,18 @@
<template> <template>
<div class="p-2"> <div class="p-2">
<a-row> <a-row>
<a-col :span="10"> <a-col :span="9">
<!--查询区域--> <!--查询区域-->
<div class="jeecg-basic-table-form-container"> <div class="jeecg-basic-table-form-container">
<a-form ref="formRef" :model="searchForm" :label-col="labelCol" :wrapper-col="wrapperCol"> <a-form ref="formRef" :model="searchForm" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row :gutter="24"> <a-row :gutter="24">
<a-col :lg="10"> <a-col :span="14">
<a-form-item name="tagName"> <a-form-item name="tagName">
<template #label><span title="服务标签名称">服务标签</span></template> <template #label><span title="服务标签名称">服务标签</span></template>
<a-input v-model:value="searchForm.tagName" allow-clear /> <a-input v-model:value="searchForm.tagName" allow-clear />
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :xl="5" :lg="6" :md="9" :sm="24"> <a-col :span="10">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons"> <span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="9"> <a-col :lg="9">
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button> <a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
@ -24,47 +24,48 @@
</a-row> </a-row>
</a-form> </a-form>
</div> </div>
<div style="background-color: #000;padding: 20px;"> <div>
<a-card :title="directive.tagName" :key="directive.id" :bordered="false" <div class="scrollable-content">
style="width: 300px;margin: 10px;" v-for="directive of tableData.records" <a-row>
:class="{ 'selected': selectedDirective.id === directive.id }" @click="handleServiceTagClick(directive)"> <a-col :span="11" :push="1" v-for="(directive, index) of tableData.records" :key="directive.id">
<div>{{ directive.description }}</div> <!-- <a-popover :placement="index % 2 == 0 ? 'left' : 'right'">
<div>{{ directive.createTime }} - {{ directive.createBy }}</div> <template #content>
</a-card> <p style="width: 10vw; word-wrap: break-word; white-space: pre-wrap">{{ directive.description ||
'暂无说明' }}</p>
</template> -->
<a-card :bordered="false" size="small" class="smart-card"
style="margin: 10px;box-shadow: 1px 1px 5px #b0b0b0;" @click="handleTagClick(directive)"
:class="{ 'selected': selectedDirective.id === directive.id }">
<div class="selected-indicator" v-if="selectedDirective.id === directive.id"></div>
<div>{{ directive.tagName }}</div>
<div> {{ directive.createBy }}</div>
<div>{{ directive.createTime }}</div>
</a-card>
<!-- </a-popover> -->
</a-col>
</a-row>
</div>
</div> </div>
</a-col> </a-col>
<a-col :span="8"> <a-col :span="8">
<div> <a-card title="服务指令" style="width: 100%">
<a-card title="服务指令" style="width: 100%"> <div class="scrollable-content">
<div v-for="derectiveInfo of selectedDirective.directives" :key="derectiveInfo.id" <a-row>
class="derectiveInfoClass" @click="directiveInfo(derectiveInfo)" <a-col :span="22" :push="1" v-for="directive of selectedDirective.directives" :key="directive.id"
:class="{ 'selected': directiveId === derectiveInfo.id }"> style="margin-top: 15px;" @click="directiveInfo(directive)">
<div class="">分类标签{{ derectiveInfo.instructionTagId_dictText }}</div> <a-badge-ribbon :text="filterDictTextByCache('period_type', directive.cycleType)" :style="{ top: '-10px' }">
<div class="directiveInfoClass">服务类别{{ derectiveInfo.categoryName }}</div> <a-card size="small">
<div class="directiveInfoClass">服务类型{{ derectiveInfo.typeName }}</div> <span :class="{ 'selected-dire': directiveId === directive.id }">
<div class="directiveInfoClass">服务指令名称{{ derectiveInfo.directiveName }}</div> {{ directive.directiveName + handleTags('', directive, '') }}
<div class="directiveInfoClass">周期类型{{ filterDictTextByCache('period_type', derectiveInfo.cycleType) }} </span>
</div> </a-card>
<div class="directiveInfoClass">服务时长(分钟){{ derectiveInfo.serviceDuration }}</div> </a-badge-ribbon>
<div class="directiveInfoClass">服务说明{{ derectiveInfo.serviceContent }}</div> </a-col>
<div class="directiveInfoClass">指令标签{{ handleTags('', derectiveInfo, '') }}</div> </a-row>
<div class="directiveInfoClass">语音文件 </div>
<span v-if="!derectiveInfo.mp3File">暂无文件</span> </a-card>
<audio controls disabled="false" v-else>
<source :src="getFileAccessHttpUrl(derectiveInfo.mp3File)">
</audio>
</div>
<div class="directiveInfoClass">视频文件
<span v-if="!derectiveInfo.mp4File">暂无文件</span>
<video controls v-else>
<source :src="getFileAccessHttpUrl(derectiveInfo.mp4File)">
</video>
</div>
</div>
</a-card>
</div>
</a-col> </a-col>
<a-col :span="6"> <a-col :span="6" style="margin-left: 1vw;">
<div> <div>
<a-card title="服务指令详情" style="width: 100%"> <a-card title="服务指令详情" style="width: 100%">
<div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div> <div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div>
@ -109,8 +110,8 @@ const derectiveInfo = ref({})
const labelCol = reactive({ const labelCol = reactive({
xs: 24, xs: 24,
sm: 4, sm: 4,
xl: 16, xl: 9,
xxl: 16 xxl: 9
}); });
const wrapperCol = reactive({ const wrapperCol = reactive({
xs: 24, xs: 24,
@ -153,7 +154,7 @@ function handleSuccess() {
*/ */
function queryList(params) { function queryList(params) {
resetSeletedDirectiveInfo() resetSeletedDirectiveInfo()
list({ pageNo: 1, pageSize: 10, tagName: searchForm.value.tagName }).then(res => { list({ pageNo: 1, pageSize: -1, tagName: searchForm.value.tagName }).then(res => {
tableData.value = res tableData.value = res
selectedDirective.value = { id: '' } selectedDirective.value = { id: '' }
}) })
@ -163,7 +164,7 @@ function queryList(params) {
* 编辑 * 编辑
* @param data * @param data
*/ */
function serviceTagEdit(data) { function tagEdit(data) {
queryById({ id: data.id }).then(item => { queryById({ id: data.id }).then(item => {
registerModal.value.edit(item); registerModal.value.edit(item);
}) })
@ -201,12 +202,12 @@ function directiveInfo(directive_) {
} }
/** /**
* 指令包点击事件 * 标签点击事件
* @param directive_ * @param directive_
*/ */
function handleServiceTagClick(directive_) { function handleTagClick(directive_) {
resetSeletedDirectiveInfo() resetSeletedDirectiveInfo()
// //
selectedDirective.value = directive_ selectedDirective.value = directive_
} }
@ -220,7 +221,7 @@ function resetSeletedDirectiveInfo() {
} }
onMounted(() => { onMounted(() => {
queryList({ pageNo: 1, pageSize: 10 }) queryList({ pageNo: 1, pageSize: -1 })
}) })
defineExpose({ defineExpose({
@ -260,11 +261,62 @@ defineExpose({
} }
.selected { .selected {
background-color: lightgreen; background: url("@/assets/icons/success.svg") no-repeat;
background-position: calc(100% - 5px) calc(100% - 5px);
background-size: auto 60%;
transition: none !important;
}
.selected-dire {
color: rgb(0, 156, 0);
font-weight: bold;
} }
.derectiveInfoClass { .derectiveInfoClass {
border: 1px solid grey; border: 1px solid grey;
margin: 5px; margin: 5px;
} }
.smart-card {
margin: 10px;
position: relative;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
//
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}
//
&:active {
transform: scale(0.98);
}
//
&.active-card {
border-left: 4px solid #1890ff;
.selected-indicator {
position: absolute;
right: 8px;
top: 8px;
width: 8px;
height: 8px;
background: #1890ff;
border-radius: 50%;
}
}
}
.scrollable-content {
height: 70vh;
/* 设置固定高度为视口的50% */
overflow-y: auto;
/* 垂直方向超出时显示滚动条 */
padding-right: 8px;
/* 防止滚动条遮挡内容 */
}
</style> </style>

View File

@ -2,35 +2,48 @@
<!-- <j-modal :title="title" :width="width" :maskClosable="false" :fullscreen="true" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭"> <!-- <j-modal :title="title" :width="width" :maskClosable="false" :fullscreen="true" :visible="visible" @ok="handleOk" :okButtonProps="{ class: { 'jee-hidden': disableSubmit } }" @cancel="handleCancel" cancelText="关闭">
<ServiceTagForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></ServiceTagForm> <ServiceTagForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"></ServiceTagForm>
</j-modal> --> </j-modal> -->
<a-drawer v-model:open="visible" v-if="visible" :title="title" width="90vw" :closable="false" <a-drawer v-model:open="visible" v-if="visible" :title="title" width="80vw" :closable="false"
:footer-style="{ textAlign: 'right' }" @close="handleCancel"> :footer-style="{ textAlign: 'right' }" @close="handleCancel">
<div style="display:flex;justify-content:space-between"> <div style="display:flex;justify-content:space-between">
<div> <div>
<a-card title="服务标签详情" style="width: 27vw"> <a-card title="服务标签详情" style="width: 25vw">
<ServiceTagForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false"> <ServiceTagForm ref="registerForm" @ok="submitCallback" :formDisabled="disableSubmit" :formBpm="false">
</ServiceTagForm> </ServiceTagForm>
</a-card> </a-card>
</div> </div>
<a-card title="服务指令" style="width: 25vw">
<template #extra>
<a href="javascript:void(0);" @click="handleQuoteDirectives">引用 </a>
<a href="javascript:void(0);" @click="handleAddDirectives">新增</a>
</template>
<div class="scrollable-content">
<a-row>
<a-col :span="22" :push="1" v-for="directive of seletedRecord.directives" :key="directive.id"
style="margin-top: 15px;" @click="directiveInfo(directive)">
<a-badge-ribbon :text="filterDictTextByCache('period_type', directive.cycleType)"
:style="{ top: '-10px' }">
<a-card size="small">
<span>
<a-popconfirm title="是否确认移除?" ok-text="确认" cancel-text="取消"
@confirm="deleteDirective(directive.id)">
<a-button type="link" danger preIcon="ic:baseline-remove-circle"></a-button>
</a-popconfirm>
</span>
<span :class="{ 'selected': selectedDirective === directive.id }">
{{ directive.directiveName + handleTags('', directive, '') }}
</span>
</a-card>
</a-badge-ribbon>
</a-col>
</a-row>
</div>
</a-card>
<div> <div>
<a-card title="服务指令" style="width: 27vw"> <a-card title="服务指令详情" style="width: 25vw">
<template #extra>
<a href="#" @click="handleQuoteDirectives">引用 </a>
<a href="#" @click="handleAddDirectives">新增</a>
</template>
<div style="padding:10px;margin-top:10px;border:1px solid red;" v-for="directive of seletedRecord.directives"
:class="{ 'selected': selectedDirective === directive.id }" @click="directiveInfo(directive)">
{{ directive.directiveName + handleTags('', directive, '') }}
<div style="float:right;">
<a href="#" @click="deleteDirective(directive.id)">移除</a>
</div>
</div>
</a-card>
</div>
<div>
<a-card title="服务指令详情" style="width: 27vw">
<div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div> <div class="">分类标签{{ filterDictTextByCache('instruction_tag', derectiveInfo.instructionTagId) }}</div>
<div class="directiveInfoClass">服务类别{{ derectiveInfo.categoryName }}</div> <div class="directiveInfoClass">服务类别{{ derectiveInfo.categoryName || derectiveInfo.categoryId_dictText }}
<div class="directiveInfoClass">服务类型{{ derectiveInfo.typeName }}</div> </div>
<div class="directiveInfoClass">服务类型{{ derectiveInfo.typeName || derectiveInfo.typeId_dictText }}</div>
<div class="directiveInfoClass">服务指令名称{{ derectiveInfo.directiveName }}</div> <div class="directiveInfoClass">服务指令名称{{ derectiveInfo.directiveName }}</div>
<div class="directiveInfoClass">周期类型{{ filterDictTextByCache('period_type', derectiveInfo.cycleType) }}</div> <div class="directiveInfoClass">周期类型{{ filterDictTextByCache('period_type', derectiveInfo.cycleType) }}</div>
<div class="directiveInfoClass">服务时长(分钟){{ derectiveInfo.serviceDuration }}</div> <div class="directiveInfoClass">服务时长(分钟){{ derectiveInfo.serviceDuration }}</div>
@ -67,7 +80,7 @@
<!-- 引用 --> <!-- 引用 -->
<a-drawer v-model:open="directiveQuoteDrawer" title="引用服务标签" width="80vw" :closable="false" <a-drawer v-model:open="directiveQuoteDrawer" title="引用服务标签" width="80vw" :closable="false"
:footer-style="{ textAlign: 'right' }"> :footer-style="{ textAlign: 'right' }">
<ServiceTagList ref="directiveServiceTagListRef"></ServiceTagList> <ServiceTagList ref="serviceTagListRef"></ServiceTagList>
<template #footer> <template #footer>
<a-button style="margin-right: 8px" @click="handleQuoteDrawCancel">关闭</a-button> <a-button style="margin-right: 8px" @click="handleQuoteDrawCancel">关闭</a-button>
<a-button type="primary" @click="handleQuoteDrawOk">确定</a-button> <a-button type="primary" @click="handleQuoteDrawOk">确定</a-button>
@ -100,7 +113,7 @@ const configServiceDirectiveListRef = ref()
const derectiveInfo = ref({}) const derectiveInfo = ref({})
const selectedDirective = ref() const selectedDirective = ref()
const directiveQuoteDrawer = ref(false) const directiveQuoteDrawer = ref(false)
const directiveServiceTagListRef = ref() const serviceTagListRef = ref()
const seletedRecord = ref({ directives: [] })// const seletedRecord = ref({ directives: [] })//
const { createMessage } = useMessage(); const { createMessage } = useMessage();
@ -113,7 +126,7 @@ function handleTags(prefix, directive_, suffix) {
let str = directive_.tagList.map(item => item.tagName).join('、 '); let str = directive_.tagList.map(item => item.tagName).join('、 ');
return prefix + str + suffix return prefix + str + suffix
} else { } else {
return ' - ' return ''
} }
} }
@ -233,7 +246,7 @@ function handleQuoteDrawOk() {
// //
seletedRecord.value.directives = [ seletedRecord.value.directives = [
...seletedRecord.value.directives, ...seletedRecord.value.directives,
...directiveServiceTagListRef.value.selectedDirective.directives.reduce((acc, current) => { ...serviceTagListRef.value.selectedDirective.directives.reduce((acc, current) => {
if (!seletedRecord.value.directives.some((item) => item.id === current.id)) { if (!seletedRecord.value.directives.some((item) => item.id === current.id)) {
acc.push(current); acc.push(current);
} }
@ -264,10 +277,20 @@ defineExpose({
</style> </style>
<style lang="less" scoped> <style lang="less" scoped>
.selected { .selected {
background-color: lightgreen; color: rgb(0, 156, 0);
font-weight: bold;
} }
.directiveInfoClass { .directiveInfoClass {
margin-top: 10px; margin-top: 10px;
} }
.scrollable-content {
height: 70vh;
/* 设置固定高度为视口的50% */
overflow-y: auto;
/* 垂直方向超出时显示滚动条 */
padding-right: 8px;
/* 防止滚动条遮挡内容 */
}
</style> </style>