3.7.1版本发布

This commit is contained in:
JEECG 2024-09-10 15:40:34 +08:00
parent 17c68f6d53
commit 13cb18b707
106 changed files with 2832 additions and 1721 deletions

View File

@ -32,6 +32,7 @@
"ant-design-vue": "^4.1.2",
"axios": "^1.6.7",
"china-area-data": "^5.0.1",
"@vant/area-data": "^1.5.1",
"clipboard": "^2.0.11",
"codemirror": "^5.65.3",
"cron-parser": "^4.9.0",

File diff suppressed because it is too large Load Diff

View File

@ -138,7 +138,9 @@
.item-style() {
li {
display: inline-block;
width: 100%;
//update-begin---author:wangshuai---date:2024-06-24---for:TV360X-1576---
width: 100% !important;
//update-end---author:wangshuai---date:2024-06-24---for:TV360X-1576---
height: @default-height;
margin: 0 !important;
line-height: @default-height;

View File

@ -10,6 +10,7 @@
:formProps="getProps"
:allDefaultValues="defaultValueRef"
:formModel="formModel"
:formName="getBindValue.name"
:setFormModel="setFormModel"
:validateFields="validateFields"
:clearValidate="clearValidate"
@ -213,6 +214,7 @@
getFieldsValue,
updateSchema,
resetSchema,
getSchemaByField,
appendSchemaByField,
removeSchemaByFiled,
resetFields,
@ -308,6 +310,7 @@
resetSchema,
setProps,
getProps,
getSchemaByField,
removeSchemaByFiled,
appendSchemaByField,
clearValidate,

View File

@ -1,6 +1,6 @@
<template>
<a-col v-bind="actionColOpt" v-if="showActionButtonGroup">
<div style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
<div class="btnArea" style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
<FormItem>
<!-- update-begin-author:zyf Date:20211213 for调换按钮前后位置-->
<slot name="submitBefore"></slot>
@ -126,3 +126,16 @@
},
});
</script>
<style lang="less" scoped>
// update-begin--author:liaozhiyang---date:20240617---forTV360X-9991753px
.btnArea {
:deep(.ant-form-item-control-input-content) {
display: flex;
align-items: center;
.ant-btn-link {
padding-left: 0;
}
}
}
// update-end--author:liaozhiyang---date:20240617---forTV360X-9991753px
</style>

View File

@ -18,6 +18,8 @@
import { useAppInject } from '/@/hooks/web/useAppInject';
import { usePermission } from '/@/hooks/web/usePermission';
import Middleware from './Middleware.vue';
import { useLocaleStoreWithOut } from '/@/store/modules/locale';
export default defineComponent({
name: 'BasicFormItem',
inheritAttrs: false,
@ -58,10 +60,16 @@
default: null,
},
// update-end-author:liaozhiyang---date:20240605---forTV360X-857
// update-begin--author:liaozhiyang---date:20240625---forTV360X-1511blur
formName: {
type: String,
default: '',
},
// update-end--author:liaozhiyang---date:20240625---forTV360X-1511blur
},
setup(props, { slots }) {
const { t } = useI18n();
const localeStore = useLocaleStoreWithOut();
const { schema, formProps } = toRefs(props) as {
schema: Ref<FormSchema>;
formProps: Ref<FormProps>;
@ -306,7 +314,7 @@
}
function renderComponent() {
const { renderComponentContent, component, field, changeEvent = 'change', valueField, componentProps, dynamicRules } = props.schema;
const { renderComponentContent, component, field, changeEvent = 'change', valueField, componentProps, dynamicRules, rules:defRules = [] } = props.schema;
const isCheck = component && ['Switch', 'Checkbox'].includes(component);
// update-begin--author:liaozhiyang---date:20231013---forQQYUN-6679input
@ -316,6 +324,10 @@
}
// update-end--author:liaozhiyang---date:20231013---forQQYUN-6679input
const eventKey = `on${upperFirst(changeEvent)}`;
const getRules = (): ValidationRule[] => {
const dyRules = isFunction(dynamicRules) ? dynamicRules(unref(getValues)) : [];
return [...dyRules, ...defRules];
};
// update-begin--author:liaozhiyang---date:20230922---forissues/752dynamicRules 使 trigger: 'blur'
const on = {
[eventKey]: (...args: Nullable<Recordable>[]) => {
@ -337,9 +349,14 @@
}
// update-end--author:liaozhiyang---date:20231013---forQQYUN-6679input
props.setFormModel(field, value);
// update-begin--author:liaozhiyang---date:20240522---forTV360X-341
props.validateFields([field]).catch((_) => {});
// update-end--author:liaozhiyang---date:20240522--forTV360X-341
// update-begin--author:liaozhiyang---date:20240625---forTV360X-1511blur
const findItem = getRules().find((item) => item?.trigger === 'blur');
if (!findItem) {
// update-begin--author:liaozhiyang---date:20240522---forTV360X-341
props.validateFields([field]).catch((_) => {});
// update-end--author:liaozhiyang---date:20240625---forTV360X-341
}
// update-end--author:liaozhiyang---date:20240625---forTV360X-1511blur
},
// onBlur: () => {
// props.validateFields([field], { triggerName: 'blur' }).catch((_) => {});
@ -366,11 +383,21 @@
}
// update-end--author:liaozhiyang---date:20240308---forQQYUN-8377formSchema props
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
// update-begin--author:sunjianlei---date:20240725---forTV360X-972
// const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
const isCreatePlaceholder = !!autoSetPlaceHolder;
// update-end----author:sunjianlei---date:20240725---forTV360X-972
// RangePicker place
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
//placeholder
propsData.placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component) + props.schema.label;
// update-begin--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
let label = isFunction(props.schema.label) ? props.schema.label() : props.schema.label;
if (localeStore.getLocale === 'en' && !(/^\s/.test(label))) {
label = ' ' + label;
}
// update-end--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
propsData.placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component) + label;
}
propsData.codeField = field;
propsData.formValues = unref(getValues);
@ -403,7 +430,10 @@
function renderLabelHelpMessage() {
//update-begin-author:taoyan date:2022-9-7 for: VUEN-2061online4 ..
//label
const { label, helpMessage, helpComponentProps, subLabel, labelLength } = props.schema;
const { label: itemLabel, helpMessage, helpComponentProps, subLabel, labelLength } = props.schema;
// update-begin--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
const label = isFunction(itemLabel) ? itemLabel() : itemLabel;
// update-end--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
let showLabel: string = label + '';
// update-begin--author:liaozhiyang---date:20240517---forTV360X-98labellabelLength
if (labelLength) {
@ -469,7 +499,7 @@
<div style="display:flex">
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */}
{/* update-begin--author:liaozhiyang---date:20240510---for【TV360X-719】表单校验不通过项滚动到可视区内 */}
<Middleware>{getContent()}</Middleware>
<Middleware formName={props.formName} fieldName={field}>{getContent()}</Middleware>
{/* update-end--author:liaozhiyang---date:20240510---for【TV360X-719】表单校验不通过项滚动到可视区内 */}
{showSuffix && <span class="suffix">{getSuffix}</span>}
</div>

View File

@ -5,12 +5,20 @@
</template>
<script setup>
import { Form } from 'ant-design-vue';
import { computed } from 'vue';
const formItemContext = Form.useInjectFormItemContext();
const formItemId = computed(() => {
return formItemContext.id.value;
});
import { ref } from 'vue';
// update-begin--author:liaozhiyang---date:20240625---forTV360X-1511blur
const formItemId = ref(null);
const props = defineProps(['formName', 'fieldName']);
if (props.formName && props.fieldName) {
formItemId.value = `${props.formName}_${props.fieldName}`;
}
// update-end--author:liaozhiyang---date:20240625---forTV360X-1511blur
</script>
<style lang="scss" scoped></style>
<style lang="less" scoped>
// update-begin--author:liaozhiyang---date:20240617---forTV360X-1253
div > :deep(.ant-picker) {
width: 100%;
}
// update-end--author:liaozhiyang---date:20240617---forTV360X-1253
</style>

View File

@ -1,5 +1,5 @@
<template>
<div :class="formDisabled ? 'jeecg-form-container-disabled jeecg-form-detail-effect' : ''">
<div :class="formDisabled ? 'jeecg-form-container-disabled jeecg-form-detail-effect' : 'jeecg-and-modal-form'">
<fieldset :disabled="formDisabled">
<slot name="detail"></slot>
</fieldset>
@ -39,6 +39,23 @@
</script>
<style scoped lang="less">
// update-begin--author:liaozhiyang---date:20240719---forTV360X-1090label
.jeecg-and-modal-form {
:deep(.ant-form-item-label) {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 6px;
> label {
line-height: 32px;
display: inline;
&::after {
margin-right: 0;
}
}
}
}
// update-end--author:liaozhiyang---date:20240719---forTV360X-1090label
.jeecg-form-container-disabled {
cursor: not-allowed;
}

View File

@ -5,7 +5,7 @@ import { handleRangeValue } from '../utils/formUtils';
import { ref, onUnmounted, unref, nextTick, watch } from 'vue';
import { isProdMode } from '/@/utils/env';
import { error } from '/@/utils/log';
import { getDynamicProps, getValueType } from '/@/utils';
import { getDynamicProps, getValueType, getValueTypeBySchema } from '/@/utils';
import { add } from "/@/components/Form/src/componentMap";
//online
import { OnlineSelectCascade, LinkTableCard, LinkTableSelect } from '@jeecg/online';
@ -137,7 +137,7 @@ export function useForm(props?: Props): UseFormReturnType {
let values = form.validate(nameList).then((values) => {
for (let key in values) {
if (values[key] instanceof Array) {
let valueType = getValueType(getProps, key);
let valueType = getValueTypeBySchema(form.getSchemaByField(key)!);
if (valueType === 'string') {
values[key] = values[key].join(',');
}

View File

@ -94,6 +94,23 @@ export function useFormEvents({
});
validateFields(validKeys).catch((_) => {});
}
/**
* 根据字段名获取schema
* @param field
*/
function getSchemaByField(field: string): Nullable<FormSchema> {
if (!isString(field)) {
return null
}
const schemaList: FormSchema[] = unref(getSchema);
const index = schemaList.findIndex((schema) => schema.field === field);
if (index !== -1) {
return cloneDeep(schemaList[index]);
}
return null
}
/**
* @description: Delete based on field name
*/
@ -270,6 +287,7 @@ export function useFormEvents({
getFieldsValue,
updateSchema,
resetSchema,
getSchemaByField,
appendSchemaByField,
removeSchemaByFiled,
resetFields,

View File

@ -22,7 +22,7 @@
showArea: propTypes.bool.def(true),
//
showAll: propTypes.bool.def(false),
//
// allprovince, city, region
saveCode: propTypes.oneOf(['province', 'city', 'region', 'all']).def('all'),
},
emits: ['options-change', 'change', 'update:value'],
@ -97,6 +97,25 @@
}
return result;
}
/**
* liaozhiyang
* 2024-06-17
* TV360X-1224省市区组件默认传到外面的值是字符串逗号分隔
* */
const send = (data) => {
let result = data;
if (result) {
if (props.saveCode === 'all') {
//
} else {
//
result = data.join(',');
}
}
emit('change', result);
emit('update:value', result);
};
function handleChange(arr, ...args) {
// update-begin--author:liaozhiyang---date:20240607---forTV360X-501
if (arr?.length) {
@ -111,11 +130,9 @@
} else {
result = arr;
}
emit('change', result);
emit('update:value', result);
send(result);
} else {
emit('change', arr);
emit('update:value', arr);
send(arr);
}
// update-end--author:liaozhiyang---date:20240607---forTV360X-501
// emitData.value = args;
@ -124,6 +141,7 @@
// state.value = result;
//update-end-author:taoyan date:2022-6-27 for: VUEN-1424vue3jvxeerp
}
return {
cascaderValue,
attrs,

View File

@ -84,7 +84,9 @@
() => {
loadItemByCode();
},
{ deep: true }
//update-begin---author:wangshuai---date:2024-06-17---for:TV360X-480---
{ deep: true, immediate: true }
//update-end---author:wangshuai---date:2024-06-17---for:TV360X-480---
);
watch(
() => props.pcode,
@ -124,6 +126,7 @@
treeValue.value = { value: null, label: null };
}
} else {
console.log("props.value:::",props.value)
loadDictItem({ ids: props.value }).then((res) => {
let values = props.value.split(',');
treeValue.value = res.map((item, index) => ({

View File

@ -10,7 +10,7 @@
import { defineComponent, computed, watch, watchEffect, ref, unref } from 'vue';
import { propTypes } from '/@/utils/propTypes';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { initDictOptions } from '/@/utils/dict/index';
import {getDictItems} from "@/api/common/api";
export default defineComponent({
name: 'JCheckbox',
@ -67,21 +67,30 @@
}
//Code,
if (props.dictCode) {
const dictData = await initDictOptions(props.dictCode);
checkOptions.value = dictData.reduce((prev, next) => {
if (next) {
const value = next['value'];
prev.push({
label: next['text'],
value: value,
color: next['color'],
});
}
return prev;
}, []);
loadDictOptions()
}
}
// code
function loadDictOptions() {
//update-begin-author:taoyan date:2022-6-21 for:
let temp = props.dictCode || '';
if (temp.indexOf(',') > 0 && temp.indexOf(' ') > 0) {
//
temp = encodeURI(temp);
}
//update-end-author:taoyan date:2022-6-21 for:
getDictItems(temp).then((res) => {
if (res) {
checkOptions.value = res.map((item) => ({value: item.value, label: item.text, color: item.color}));
//console.info('res', dictOptions.value);
} else {
console.error('getDictItems error: : ', res);
checkOptions.value = [];
}
});
}
/**
* change事件
* @param $event

View File

@ -44,6 +44,9 @@
import 'codemirror/addon/hint/anyword-hint.js';
//
import 'codemirror/addon/edit/matchbrackets';
//
import 'codemirror/addon/display/placeholder.js';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { useDesign } from '/@/hooks/web/useDesign';
import { isJsonObjectString } from '/@/utils/is.ts';
@ -356,6 +359,10 @@
.CodeMirror{
border: 1px solid #ddd;
}
.CodeMirror pre.CodeMirror-placeholder {
color: #cacaca;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
}
}
.CodeMirror-hints.idea,
.CodeMirror-hints.monokai {

View File

@ -17,6 +17,8 @@
props: {
value: propTypes.string.def(''),
disabled: propTypes.bool.def(false),
//
autoFocus: propTypes.bool.def(true),
},
emits: ['change', 'update:value'],
setup(props, { emit, attrs }) {

View File

@ -183,6 +183,16 @@
if (file.status === 'error') {
createMessage.error(`${file.name} 上传失败.`);
}
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1640
if (file.status === 'done' && file.response.success === false) {
const failIndex = uploadFileList.value.findIndex((item) => item.uid === file.uid);
if (failIndex != -1) {
uploadFileList.value.splice(failIndex, 1);
}
createMessage.warning(file.response.message);
return;
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1640
let fileUrls = [];
let noUploadingFileCount = 0;
if (file.status != 'uploading') {

View File

@ -17,6 +17,7 @@
v-if="selectLocation === 'right'"
v-model:value="selectVal"
@change="handleSelectChange"
:style="{width:props.selectWidth}"
>
<a-select-option v-for="item in options" :key="item.value">{{ item.label }}</a-select-option>
</a-select>
@ -33,6 +34,7 @@
selectLocation: propTypes.oneOf(['left', 'right']).def('right'),
selectPlaceholder: propTypes.string.def(''),
inputPlaceholder: propTypes.string.def(''),
selectWidth:propTypes.string.def('auto'),
});
const emit = defineEmits(['update:value', 'change']);
const selectVal = ref<string>();

View File

@ -23,8 +23,9 @@
:groupId="uniqGroupId"
:param="param"
:showAdvancedButton="showAdvancedButton"
@ok="callBack"
:getContainer="getContainer"
:getFormValues="getFormValues"
@ok="callBack"
></JPopupOnlReportModal>
</a-form-item>
<!-- update-end--author:liaozhiyang---date:20240515---forQQYUN-9260必填模式下会影响到弹窗内antd组件的样式 -->
@ -56,6 +57,7 @@
groupId: propTypes.string.def(''),
formElRef: propTypes.object,
setFieldsValue: propTypes.func,
getFormValues: propTypes.func,
getContainer: propTypes.func,
fieldConfig: {
type: Array,

View File

@ -15,9 +15,10 @@
:sorter="sorter"
:groupId="''"
:param="param"
@ok="callBack"
:getFormValues="getFormValues"
:getContainer="getContainer"
:showAdvancedButton="showAdvancedButton"
@ok="callBack"
/>
</a-form-item>
<!-- update-end--author:liaozhiyang---date:20240515---forQQYUN-9260必填模式下会影响到弹窗内antd组件的样式 -->
@ -56,6 +57,7 @@
multi: propTypes.bool.def(false),
param: propTypes.object.def({}),
spliter: propTypes.string.def(','),
getFormValues: propTypes.func,
getContainer: propTypes.func,
showAdvancedButton: propTypes.bool.def(true),
},

View File

@ -39,8 +39,10 @@
function emitArray() {
let arr = [];
let begin = beginValue.value || '';
let end = endValue.value || '';
// update-begin--author:liaozhiyang---date:20240704---forTV360X-17490
let begin = beginValue.value ?? '';
let end = endValue.value ?? '';
// update-end--author:liaozhiyang---date:20240704---forTV360X-17490
arr.push(begin);
arr.push(end);
emit('change', arr);

View File

@ -14,11 +14,12 @@
@focus="handleAsyncFocus"
@search="loadData"
@change="handleAsyncChange"
@popupScroll="handlePopupScroll"
>
<template #notFoundContent>
<a-spin size="small" />
</template>
<a-select-option v-for="d in options" :key="d.value" :value="d.value">{{ d.text }}</a-select-option>
<a-select-option v-for="d in options" :key="d?.value" :value="d?.value">{{ d?.text }}</a-select-option>
</a-select>
<!--字典下拉搜素-->
<a-select
@ -36,7 +37,7 @@
<template #notFoundContent>
<a-spin v-if="loading" size="small" />
</template>
<a-select-option v-for="d in options" :key="d.value" :value="d.value">{{ d.text }}</a-select-option>
<a-select-option v-for="d in options" :key="d?.value" :value="d?.value">{{ d?.text }}</a-select-option>
</a-select>
</template>
@ -95,6 +96,11 @@
const lastLoad = ref(0);
// valuetext
const loadSelectText = ref(true);
// () -
let isHasData = true;
let scrollLoading = false;
let pageNo = 1;
let searchKeyword = '';
//
const isDictTable = computed(() => {
@ -152,6 +158,12 @@
if (!isDictTable.value) {
return;
}
// update-begin--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
pageNo = 1;
isHasData = true;
searchKeyword = value;
// update-end--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
lastLoad.value += 1;
const currentLoad = unref(lastLoad);
options.value = [];
@ -164,7 +176,7 @@
defHttp
.get({
url: `/sys/dict/loadDict/${props.dict}`,
params: { keyword: keywordInfo, pageSize: props.pageSize },
params: { keyword: keywordInfo, pageSize: props.pageSize, pageNo },
})
.then((res) => {
loading.value = false;
@ -173,6 +185,13 @@
return;
}
options.value = res;
// update-begin--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
pageNo++;
// update-end--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
} else {
// update-begin--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
pageNo == 1 && (isHasData = false);
// update-end--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
}
});
}, 300);
@ -195,10 +214,12 @@
key: value,
label: res,
};
selectedAsyncValue.value = { ...obj };
if (props.value == value) {
selectedAsyncValue.value = { ...obj };
}
//update-begin-author:taoyan date:2022-8-11 for: change--online
if(props.immediateChange == true){
emit('change', value);
emit('change', props.value);
}
//update-end-author:taoyan date:2022-8-11 for: change--online
}
@ -243,18 +264,31 @@
if (!dict) {
console.error('搜索组件未配置字典项');
} else {
// update-begin--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
pageNo = 1;
isHasData = true;
searchKeyword = '';
// update-end--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
//
loading.value = true;
let keywordInfo = getKeywordParam('');
defHttp
.get({
url: `/sys/dict/loadDict/${dict}`,
params: { pageSize: pageSize, keyword: keywordInfo },
params: { pageSize: pageSize, keyword: keywordInfo, pageNo },
})
.then((res) => {
loading.value = false;
if (res && res.length > 0) {
options.value = res;
// update-begin--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
pageNo++;
// update-end--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
} else {
// update-begin--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
pageNo == 1 && (isHasData = false);
// update-end--author:liaozhiyang---date:20240731---forTV360X-1898JsearchSelect
}
});
}
@ -355,11 +389,57 @@
// update-begin--author:liaozhiyang---date:20240523---forTV360X-26
const handleAsyncFocus = () => {
// update-begin--author:liaozhiyang---date:20240709---forissues/6681
(isObject(selectedAsyncValue.value) || selectedAsyncValue.value?.length) && isDictTable.value && props.async && initDictTableData();
if ((isObject(selectedAsyncValue.value) || selectedAsyncValue.value?.length) && isDictTable.value && props.async) {
// update-begin--author:liaozhiyang---date:20240809---forTV360X-2062()()
options.value = [];
// update-end--author:liaozhiyang---date:20240809---forTV360X-2062()()
initDictTableData();
}
// update-end--author:liaozhiyang---date:20240709---forissues/6681
attrs.onFocus?.();
};
// update-end--author:liaozhiyang---date:20240523---forTV360X-26
/**
* 2024-07-30
* liaozhiyang
* TV360X-1898JsearchSelect组件传入字典表格式则支持滚动加载
* */
const handlePopupScroll = async (e) => {
//
if (isDictTable.value) {
const { target } = e;
const { scrollTop, scrollHeight, clientHeight } = target;
if (!scrollLoading && isHasData && scrollTop + clientHeight >= scrollHeight - 10) {
scrollLoading = true;
let keywordInfo = getKeywordParam(searchKeyword);
defHttp
.get({ url: `/sys/dict/loadDict/${props.dict}`, params: { pageSize: props.pageSize, keyword: keywordInfo, pageNo } })
.then((res) => {
loading.value = false;
if (res?.length > 0) {
//
if (JSON.stringify(res[0]) === JSON.stringify(options.value[0])) {
isHasData = false;
return;
}
options.value.push(...res);
pageNo++;
} else {
isHasData = false;
}
})
.finally(() => {
scrollLoading = false;
})
.catch(() => {
pageNo != 1 && pageNo--;
});
}
}
};
return {
attrs,
options,
@ -373,6 +453,7 @@
handleChange,
handleAsyncChange,
handleAsyncFocus,
handlePopupScroll,
};
},
});

View File

@ -152,6 +152,11 @@
let result = typeof props.value == 'string' ? values.join(',') : values;
emit('update:value', result);
emit('change', result);
// update-begin--author:liaozhiyang---date:20240627---forTV360X-1648
if (!values || values.length == 0) {
emit('select', null, null);
}
// update-end--author:liaozhiyang---date:20240627---forTV360X-1648
};
// update-end--author:liaozhiyang---date:20240527---forTV360X-414(JSelectUser)

View File

@ -91,6 +91,17 @@
}
});
watch(
() => props.dictCode,
() => {
if (props.dictCode) {
loadDictOptions();
} else {
dictOptions.value = props.options;
}
}
);
watch(
() => props.value,
(val) => {

View File

@ -305,7 +305,10 @@
} else if (info.file.status === 'error') {
createMessage.error(`${info.file.name} 上传失败.`);
}
fileList.value = fileListTemp;
// update-begin--author:liaozhiyang---date:20240628---forissues/1273JUploadbeforeUpload
// beforeUpload falsestatus
info.file.status && (fileList.value = fileListTemp);
// update-end--author:liaozhiyang---date:20240628---forissues/1273JUploadbeforeUpload
if (info.file.status === 'done' || info.file.status === 'removed') {
//returnUrltrue
if (props.returnUrl) {

View File

@ -1,6 +1,9 @@
<template>
<div>
<a-row class="j-select-row" type="flex" :gutter="8">
<div v-if="isDetailsMode">
<p class="detailStr" :title="detailStr">{{ detailStr }}</p>
</div>
<a-row v-else class="j-select-row" type="flex" :gutter="8">
<a-col class="left" :class="{ full: !showButton }">
<!-- 显示加载效果 -->
<a-input v-if="loading" readOnly placeholder="加载中…">
@ -32,7 +35,7 @@
</div>
</template>
<script lang="ts">
import { defineComponent, ref, inject, reactive } from 'vue';
import { defineComponent, ref, inject, reactive, watch } from 'vue';
import { propTypes } from '/@/utils/propTypes';
import { useAttrs } from '/@/hooks/core/useAttrs';
import { LoadingOutlined } from '@ant-design/icons-vue';
@ -59,6 +62,8 @@
maxTagCount: propTypes.number,
// buttonIcon
buttonIcon: propTypes.string.def(''),
// TV360X-1002
isDetailsMode: propTypes.bool.def(false),
},
emits: ['handleOpen', 'change'],
setup(props, { emit, refs }) {
@ -67,7 +72,7 @@
//
const selectValues = inject('selectValues') || ref({});
const attrs = useAttrs();
const detailStr = ref('');
/**
* 打开弹出框
*/
@ -89,12 +94,28 @@
emit('change', value);
}
// -update-begin--author:liaozhiyang---date:20240617---forTV360X-1002
watch(
[selectValues, options],
() => {
if (props.isDetailsMode) {
if (Array.isArray(selectValues.value) && Array.isArray(options.value)) {
const result = options.value.map((item) => item.label);
detailStr.value = result.join(',');
}
}
},
{ immediate: true }
);
// -update-end--author:liaozhiyang---date:20240617---forTV360X-1002
return {
attrs,
selectValues,
options,
handleChange,
openModal,
detailStr,
};
},
});
@ -119,4 +140,10 @@
display: none !important;
}
}
.detailStr {
margin: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
</style>

View File

@ -80,7 +80,7 @@
const queryUrl = getQueryUrl();
const [{ visibleChange, checkedKeys, getCheckStrictly, getSelectTreeData, onCheck, onLoadData, treeData, checkALL, expandAll, onSelect }] =
useTreeBiz(treeRef, queryUrl, getBindValue, props);
useTreeBiz(treeRef, queryUrl, getBindValue, props, emit);
const searchInfo = ref(props.params);
const tree = ref([]);
//treeNodekeytreeData

View File

@ -12,8 +12,8 @@
wrapClassName="j-popup-modal"
@visible-change="visibleChange"
>
<div class="jeecg-basic-table-form-container" v-if="showSearchFlag">
<a-form ref="formRef" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol" @keyup.enter.native="searchQuery">
<div class="jeecg-basic-table-form-container">
<a-form ref="formRef" v-if="showSearchFlag" :model="queryParam" :label-col="labelCol" :wrapper-col="wrapperCol" @keyup.enter.native="searchQuery">
<a-row :gutter="24">
<template v-for="(item, index) in queryInfo">
<template v-if="item.hidden === '1'">
@ -31,8 +31,8 @@
<a-col :md="8" :sm="8" v-if="showAdvancedButton">
<span style="float: left; overflow: hidden" class="table-page-search-submitButtons">
<a-col :lg="6">
<a-button type="primary" preIcon="ant-design:reload-outlined" @click="searchReset">重置</a-button>
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery" style="margin-left: 8px">查询</a-button>
<a-button type="primary" preIcon="ant-design:search-outlined" @click="searchQuery">查询</a-button>
<a-button preIcon="ant-design:reload-outlined" @click="searchReset" style="margin-left: 8px">重置</a-button>
<a @click="handleToggleSearch" style="margin-left: 8px">
{{ toggleSearchStatus ? '收起' : '展开' }}
<Icon :icon="toggleSearchStatus ? 'ant-design:up-outlined' : 'ant-design:down-outlined'" />
@ -59,6 +59,12 @@
@change="handleChangeInTable"
>
<template #tableTitle></template>
<template #bodyCell="{text, column}">
<template v-if="column.fieldType === 'Image'">
<span v-if="!text" style="font-size: 12px; font-style: italic">无图片</span>
<img v-else :src="getImgView(text)" alt="图片不存在" class="cellIamge" @click="viewOnlineCellImage($event, text)" />
</template>
</template>
</BasicTable>
</BasicModal>
</div>
@ -71,6 +77,8 @@
import { useAttrs } from '/@/hooks/core/useAttrs';
import { usePopBiz } from '/@/components/jeecg/OnLine/hooks/usePopBiz';
import { useMessage } from '/@/hooks/web/useMessage';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { createImgPreview } from '/@/components/Preview/index';
export default defineComponent({
name: 'JPopupOnlReportModal',
@ -82,9 +90,9 @@
loading: true,
}),
},
props: ['multi', 'code', 'sorter', 'groupId', 'param','showAdvancedButton'],
props: ['multi', 'code', 'sorter', 'groupId', 'param','showAdvancedButton', 'getFormValues'],
emits: ['ok', 'register'],
setup(props, { emit, refs }) {
setup(props, { emit }) {
const { createMessage } = useMessage();
const labelCol = reactive({
xs: { span: 24 },
@ -242,6 +250,41 @@
queryParam.value = {};
loadData(1);
}
/**
* 2024-07-24
* liaozhiyang
* TV360X-1756报表添加图片类型
* 图片
* @param text
*/
function getImgView(text) {
if (text && text.indexOf(',') > 0) {
text = text.substring(0, text.indexOf(','));
}
return getFileAccessHttpUrl(text);
}
/**
* 2024-07-24
* liaozhiyang
* TV360X-1756报表添加图片类型
* 预览列表 cell 图片
* @param text
*/
function viewOnlineCellImage(e, text) {
e.stopPropagation();
if (text) {
let imgList: any = [];
let arr = text.split(',');
for (let str of arr) {
if (str) {
imgList.push(getFileAccessHttpUrl(str));
}
}
createImgPreview({ imageList: imgList });
}
}
return {
attrs,
register,
@ -272,6 +315,8 @@
handleToggleSearch,
searchQuery,
searchReset,
getImgView,
viewOnlineCellImage,
};
},
});
@ -290,4 +335,12 @@
:deep(.jeecg-basic-table .ant-table-wrapper .ant-table-title){
min-height: 0;
}
.cellIamge {
height: 25px !important;
margin: 0 auto;
max-width: 80px;
font-size: 12px;
font-style: italic;
cursor: pointer;
}
</style>

View File

@ -29,6 +29,7 @@
:rowSelection="rowSelection"
:indexColumnProps="indexColumnProps"
:afterFetch="afterFetch"
:beforeFetch="beforeFetch"
>
<!-- update-begin-author:taoyan date:2022-5-25 for: VUEN-1112一对多 用户选择 未显示选择条数及清空 -->
<template #tableTitle></template>
@ -267,6 +268,17 @@
maxHeight.value = clientHeight > 600 ? 600 : clientHeight;
// update-end--author:liaozhiyang---date:20240607---forTV360X-30510
//update-begin---author:wangshuai---date:2024-07-03---for:TV360X-1629---
/**
* 请求之前根据创建时间排序
*
* @param params
*/
function beforeFetch(params) {
return Object.assign({ column: 'createTime', order: 'desc' }, params);
}
//update-end---author:wangshuai---date:2024-07-03---for:TV360X-1629---
return {
//config,
handleOk,
@ -287,6 +299,7 @@
afterFetch,
handleCancel,
maxHeight,
beforeFetch,
};
},
});

View File

@ -39,12 +39,22 @@ export const useCodeHinting = (CodeMirror, keywords, language) => {
// .
const curLineCode = cm.getLine(cur.line);
for (let i = 0, len = customKeywords.length; i < len; i++) {
const k = curLineCode.substring(-1, customKeywords[i].length);
const k = curLineCode.slice(-(customKeywords[i].length + 1), -1);
if (customKeywords.includes(k)) {
recordKeyword = k;
break;
}
}
} else {
// .this(.)
const curLineCode = cm.getLine(cur.line);
for (let i = 0, len = customKeywords.length; i < len; i++) {
const k = curLineCode.slice(start - (customKeywords[i].length + 1), start);
if (k.substr(-1) === '.' && customKeywords.includes(k.replace('.', ''))) {
recordKeyword = k.replace('.', '');
break;
}
}
}
const findIdx = (a, b) => a.toLowerCase().indexOf(b.toLowerCase());
let list = currentKeywords.filter((item) => {

View File

@ -2,7 +2,7 @@ import { inject, reactive, ref, watch, unref, Ref } from 'vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { isEmpty } from '@/utils/is';
export function useSelectBiz(getList, props, emit) {
export function useSelectBiz(getList, props, emit?) {
//
const selectOptions = inject('selectOptions', ref<Array<object>>([]));
//
@ -120,7 +120,7 @@ export function useSelectBiz(getList, props, emit) {
props.showSelected && initSelectRows();
} else {
// update-begin--author:liaozhiyang---date:20240517---forQQYUN-9366
emit('close');
emit?.('close');
// update-end--author:liaozhiyang---date:20240517---forQQYUN-9366
}
}

View File

@ -35,6 +35,7 @@ export interface FormActionType {
resetSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
setProps: (formProps: Partial<FormProps>) => Promise<void>;
getProps: ComputedRef<Partial<FormProps>>;
getSchemaByField: (field: string) => Nullable<FormSchema>;
removeSchemaByFiled: (field: string | string[]) => Promise<void>;
appendSchemaByField: (schema: FormSchema, prefixField: string | undefined, first?: boolean | undefined) => Promise<void>;
validateFields: (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>;
@ -131,7 +132,9 @@ export interface FormSchema {
// Variable name bound to v-model Default value
valueField?: string;
// Label name
label: string | VNode;
// update-begin--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
label: string | VNode | Fn;
// update-end--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
// Auxiliary text
subLabel?: string;
// Help text on the right side of the text

View File

@ -1,4 +1,4 @@
import REGION_DATA from 'china-area-data';
import {pcaa as REGION_DATA} from "@/utils/areaData/pcaUtils";
/**
* Area 属性all的类型
@ -18,7 +18,7 @@ class Area {
/**
* 构造器
* @param express
* @param pcaa
*/
constructor(pcaa?) {
if (!pcaa) {
@ -101,6 +101,11 @@ const jeecgAreaData = new Area();
// code
const getAreaTextByCode = function (code) {
let index = 3;
// update-begin--author:liaozhiyang---date:20240617---forTV360X-1210online
if (code && ['82', '81'].includes(code.substring(0, 2))) {
index = 2;
}
// update-end--author:liaozhiyang---date:20240617---forTV360X-1210online
//update-begin-author:liusq---date:20220531--for: codecodecode ---
if (code && code.includes(',')) {
index = code.split(",").length;

View File

@ -1,4 +1,4 @@
import REGION_DATA from 'china-area-data';
import {pcaa as REGION_DATA} from "@/utils/areaData/pcaUtils";
import { cloneDeep } from 'lodash-es';
// code转汉字大对象

View File

@ -53,6 +53,7 @@
Empty,
Pagination,
},
emits: ['update:value'],
props: {
currentList: propTypes.any.def([]),
clearSelect: propTypes.bool.def(false),
@ -141,6 +142,7 @@
}
}
}
emit('update:value', currentSelect.value);
}
/**

View File

@ -11,37 +11,37 @@
<a-tabs style="padding-left: 15px;padding-right: 15px">
<a-tab-pane tab="方向性图标" key="1">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="directionIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="directionIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
<a-tab-pane tab="指示性图标" key="2">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="suggestionIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="suggestionIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
<a-tab-pane tab="编辑类图标" key="3">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="editIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="editIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
<a-tab-pane tab="数据类图标" key="4">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="dataIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="dataIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
<a-tab-pane tab="网站通用图标" key="5">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="webIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="webIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
<a-tab-pane tab="品牌和标识" key="6">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="logoIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-svg-mode="isSvgMode" :current-list="logoIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
<a-tab-pane tab="其他" key="7">
<a-form-item-rest>
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-page="true" :is-search="true" :is-svg-mode="isSvgMode" :current-list="otherIcons" :value="currentSelect" />
<icon-list ref="iconListRef" :clear-select="clearSelect" :copy="copy" :is-page="true" :is-search="true" :is-svg-mode="isSvgMode" :current-list="otherIcons" v-model:value="selectIcon" />
</a-form-item-rest>
</a-tab-pane>
</a-tabs>
@ -94,6 +94,7 @@
const isSvgMode = props.mode === 'svg';
const icons = isSvgMode ? getSvgIcons() : getIcons();
const selectIcon = ref('');
const currentSelect = ref('');
const { t } = useI18n();
@ -170,7 +171,7 @@
* 图标弹窗确定事件
*/
function handleOk() {
currentSelect.value = iconListRef.value.getIcon();
currentSelect.value = selectIcon.value;
iconOpen.value = false;
}

View File

@ -77,6 +77,9 @@
maxTagCount: 1,
//
maxTagPlaceholder: ({ length }) => '+' + length,
// -update-begin--author:liaozhiyang---date:20240617---forTV360X-1002
isDetailsMode: cellProps.value.disabledTable,
// -update-end--author:liaozhiyang---date:20240617---forTV360X-1002
};
});

View File

@ -52,6 +52,9 @@
maxTagCount: 1,
//
maxTagPlaceholder: ({ length }) => '+' + length,
// -update-begin--author:liaozhiyang---date:20240617---forTV360X-1002
isDetailsMode: cellProps.value.disabledTable,
// -update-end--author:liaozhiyang---date:20240617---forTV360X-1002
};
});

View File

@ -25,6 +25,7 @@
:dropMenuList="getDropdownList"
popconfirm
v-if="dropDownActions && getDropdownList.length > 0"
:getPopupContainer="dropdownGetPopupContainer"
>
<slot name="more"></slot>
<!-- 设置插槽 -->
@ -71,6 +72,10 @@
const { prefixCls } = useDesign('basic-table-action');
const dropdownCls = `${prefixCls}-dropdown`;
let table: Partial<TableActionType> = {};
const tempActionsAuth = {};
const tempDropdownListAuth = {};
if (!props.outside) {
table = useTableContext();
}
@ -93,7 +98,17 @@
const getActions = computed(() => {
return (toRaw(props.actions) || [])
.filter((action) => {
return hasPermission(action.auth) && isIfShow(action);
// -update-begin--author:liaozhiyang---date:20240619---forTV360X-528hasPermission
const auth: any = action.auth;
let authResult;
if (action.auth && typeof tempActionsAuth[auth] === 'boolean') {
authResult = tempActionsAuth[auth];
} else {
authResult = hasPermission(action.auth);
action.auth && (tempActionsAuth[auth] = authResult);
}
return authResult && isIfShow(action);
// -update-end--author:liaozhiyang---date:20240619---forTV360X-528hasPermission
})
.map((action) => {
const { popConfirm } = action;
@ -121,7 +136,17 @@
const getDropdownList = computed((): any[] => {
//dropdown,线
const list = (toRaw(props.dropDownActions) || []).filter((action) => {
return hasPermission(action.auth) && isIfShow(action);
// -update-begin--author:liaozhiyang---date:20240619---forTV360X-528hasPermission
const auth: any = action.auth;
let authResult;
if (action.auth && typeof tempDropdownListAuth[auth] === 'boolean') {
authResult = tempDropdownListAuth[auth];
} else {
authResult = hasPermission(action.auth);
action.auth && (tempDropdownListAuth[auth] = authResult);
}
return authResult && isIfShow(action);
// -update-end--author:liaozhiyang---date:20240619---forTV360X-528hasPermission
});
return list.map((action, index) => {
const { label, popConfirm } = action;
@ -129,6 +154,13 @@
if (popConfirm) {
const overlayClassName = popConfirm.overlayClassName;
popConfirm.overlayClassName = `${overlayClassName ? overlayClassName : ''} ${prefixCls}-popconfirm`;
// update-begin--author:liaozhiyang---date:20240814---forissues/7028
if (!popConfirm.getPopupContainer) {
popConfirm.getPopupContainer = () => {
return (table as any)?.wrapRef?.value ?? document.body;
};
}
// update-end--author:liaozhiyang---date:20240814---forissues/7028
}
// update-end--author:liaozhiyang---date:20240105---forissues/951table
// update-begin--author:liaozhiyang---date:20240108---forissues/936
@ -196,8 +228,12 @@
});
isInButton && e.stopPropagation();
}
return { prefixCls, getActions, getDropdownList, getDropdownSlotList, getAlign, onCellClick, getTooltip, dropdownCls };
// update-begin--author:liaozhiyang---date:20240814---forissues/7028
const dropdownGetPopupContainer = () => {
return (table as any)?.wrapRef?.value ?? document.body;
};
// update-end--author:liaozhiyang---date:20240814---forissues/7028
return { prefixCls, getActions, getDropdownList, getDropdownSlotList, getAlign, onCellClick, getTooltip, dropdownCls, dropdownGetPopupContainer };
},
});
</script>

View File

@ -91,7 +91,7 @@
</template>
<script lang="ts">
import type { BasicColumn, ColumnChangeParam } from '../../types/table';
import { defineComponent, ref, reactive, toRefs, watchEffect, nextTick, unref, computed } from 'vue';
import { defineComponent, ref, reactive, toRefs, watchEffect, nextTick, unref, computed, watch } from 'vue';
import { Tooltip, Popover, Checkbox, Divider } from 'ant-design-vue';
import type { CheckboxChangeEvent } from 'ant-design-vue/lib/checkbox/interface';
import { SettingOutlined, DragOutlined } from '@ant-design/icons-vue';
@ -107,6 +107,7 @@
import { cloneDeep, omit } from 'lodash-es';
import Sortablejs from 'sortablejs';
import type Sortable from 'sortablejs';
import { useLocaleStoreWithOut } from '/@/store/modules/locale';
interface State {
checkAll: boolean;
@ -156,6 +157,10 @@
const columnListRef = ref<ComponentRef>(null);
const restAfterOptions = {
value: null,
};
const state = reactive<State>({
checkAll: true,
checkedList: [],
@ -181,7 +186,7 @@
let sortable: Sortable;
const sortableOrder = ref<string[]>();
const localeStore = useLocaleStoreWithOut();
//
const { saveSetting, resetSetting } = useColumnsCache(
{
@ -191,6 +196,7 @@
plainSortOptions,
sortableOrder,
checkIndex,
restAfterOptions,
},
setColumns,
handleColumnFixed
@ -210,6 +216,14 @@
checkIndex.value = !!values.showIndexColumn;
checkSelect.value = !!values.rowSelection;
});
// update-begin--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
watch(localeStore, () => {
const columns = getColumns();
plainOptions.value = columns;
plainSortOptions.value = columns;
cachePlainOptions.value = columns;
});
// update-end--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
function getColumns() {
const ret: Options[] = [];
@ -227,7 +241,7 @@
const columns = getColumns();
const checkList = table
.getColumns({ ignoreAction: true })
.getColumns({ ignoreAction: true, ignoreIndex: true })
.map((item) => {
if (item.defaultHidden) {
return '';
@ -255,6 +269,9 @@
}
state.isInit = true;
state.checkedList = checkList;
// update-begin--author:liaozhiyang---date:20240612---forTV360X-105[]
state.checkAll = columns.length === checkList.length;
// update-end--author:liaozhiyang---date:20240612---forTV360X-105[]
}
// checkAll change
@ -272,7 +289,9 @@
const indeterminate = computed(() => {
const len = plainOptions.value.length;
let checkedLen = state.checkedList.length;
unref(checkIndex) && checkedLen--;
// update-begin--author:liaozhiyang---date:20240612---forTV360X-105[]
// unref(checkIndex) && checkedLen--;
// update-end--author:liaozhiyang---date:20240612---forTV360X-105[]
return checkedLen > 0 && checkedLen < len;
});
@ -289,23 +308,29 @@
// reset columns
function reset() {
// state.checkedList = [...state.defaultCheckList];
// update-begin--author:liaozhiyang---date:20231103---forissues/825tabel[]
state.checkedList = table
.getColumns({ ignoreAction: true })
.map((item) => {
return item.dataIndex || item.title;
})
.filter(Boolean) as string[];
// update-end--author:liaozhiyang---date:20231103---forissues/825tabel[]
state.checkAll = true;
plainOptions.value = unref(cachePlainOptions);
plainSortOptions.value = unref(cachePlainOptions);
// update-begin--author:liaozhiyang---date:20240612---forTV360X-105[]
setColumns(table.getCacheColumns());
if (sortableOrder.value) {
sortable.sort(sortableOrder.value);
}
resetSetting();
setTimeout(() => {
const columns = getColumns();
// state.checkedList = [...state.defaultCheckList];
// update-begin--author:liaozhiyang---date:20231103---forissues/825tabel[]
state.checkedList = table
.getColumns({ ignoreAction: true })
.map((item) => {
return item.dataIndex || item.title;
})
.filter(Boolean) as string[];
// update-end--author:liaozhiyang---date:20231103---forissues/825tabel[]
state.checkAll = true;
plainOptions.value = unref(cachePlainOptions);
plainSortOptions.value = unref(cachePlainOptions);
restAfterOptions.value = columns;
if (sortableOrder.value) {
sortable.sort(sortableOrder.value);
}
resetSetting();
}, 100);
// update-end--author:liaozhiyang---date:20240612---forTV360X-105[]
}
// Open the pop-up window for drag and drop initialization
@ -350,6 +375,9 @@
// setColumns(columns);
// update-end--author:liaozhiyang---date:20240522---forTV360X-108
// update-end--author:liaozhiyang---date:20230904---forQQYUN-6424table
// update-begin--author:liaozhiyang---date:20240611---forTV360X-105[]
restAfterOptions.value = null;
// update-end--author:liaozhiyang---date:20240611---forTV360X-105[]
},
});
// order

View File

@ -56,14 +56,23 @@ function handleIndexColumn(propsRef: ComputedRef<BasicTableProps>, getPagination
columns.splice(indIndex, 1);
}
});
// update-begin--author:liaozhiyang---date:20240611---forTV360X-105[]
if (columns.length === 0 && showIndexColumn) {
const indIndex = columns.findIndex((column) => column.flag === INDEX_COLUMN_FLAG);
if (indIndex === -1) {
pushIndexColumns = true;
}
}
// update-end--author:liaozhiyang---date:20240611---forTV360X-105[]
if (!pushIndexColumns) return;
const isFixedLeft = columns.some((item) => item.fixed === 'left');
columns.unshift({
flag: INDEX_COLUMN_FLAG,
width: 50,
// update-begin--author:liaozhiyang---date:20240724---forTV360X-1634
width: propsRef.value.size === 'large' ? 65 : 50,
// update-end--author:liaozhiyang---date:20240724---forTV360X-1634
title: t('component.table.index'),
align: 'center',
customRender: ({ index }) => {
@ -107,7 +116,13 @@ export function useColumns(
const getColumnsRef = computed(() => {
const columns = cloneDeep(unref(columnsRef));
// update-begin--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
if (isArray(columns)) {
columns.forEach((item) => {
item.title = isFunction(item.title) ? item.title() : item.title;
});
}
// update-end--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
handleIndexColumn(propsRef, getPaginationRef, columns);
handleActionColumn(propsRef, columns);
// update-begin--author:sunjianlei---date:220230630---forQQYUN-5571
@ -346,3 +361,4 @@ export function formatCell(text: string, format: CellFormat, record: Recordable,
return text;
}
}

View File

@ -97,7 +97,14 @@ export function useColumnsCache(opt, setColumns, handleColumnFixed) {
/** 保存列配置 */
function saveSetting() {
const { checkedList } = opt.state;
const sortedList = unref(opt.plainSortOptions).map((item) => item.value);
// update-begin--author:liaozhiyang---date:20240611---forTV360X-105[]
let sortedList = [];
if (opt.restAfterOptions.value) {
sortedList = opt.restAfterOptions.value.map((item) => item.value);
} else {
sortedList = unref(opt.plainSortOptions).map((item) => item.value);
}
// update-end--author:liaozhiyang---date:20240611---forTV360X-105[]
$ls.set(cacheKey.value, {
//
checkedList,

View File

@ -219,22 +219,27 @@ export function useCustomSelection(
});
// 选择全部
function onSelectAll(checked: boolean) {
function onSelectAll(checked: boolean, flag = 'currentPage') {
// update-begin--author:liaozhiyang---date:20231122---for【issues/5577】BasicTable组件全选和取消全选时不触发onSelectAll事件
if (unref(propsRef)?.rowSelection?.onSelectAll) {
allSelected = checked;
changeRows = getInvertRows(selectedRows.value);
changeRows = getInvertRows(selectedRows.value, checked, flag);
}
// update-end--author:liaozhiyang---date:20231122---for【issues/5577】BasicTable组件全选和取消全选时不触发onSelectAll事件
// 取消全选
if (!checked) {
// update-begin--author:liaozhiyang---date:20240510---for【issues/1173】取消全选只是当前页面取消
// selectedKeys.value = [];
// selectedRows.value = [];
// emitChange('all');
flattedData.value.forEach((item) => {
updateSelected(item, false);
});
// update-begin--author:liaozhiyang---date:20240808---for【issues/6958】取消没触发onSelectAll事件跨页选中后 changeRows 为空
if (flag === 'allPage') {
selectedKeys.value = [];
selectedRows.value = [];
} else {
flattedData.value.forEach((item) => {
updateSelected(item, false);
});
}
emitChange('all');
// update-end--author:liaozhiyang---date:20240808---for【issues/6958】取消没触发onSelectAll事件跨页选中后 changeRows 为空
// update-end--author:liaozhiyang---date:20240510---for【issues/1173】取消全选只是当前页面取消
return;
}
@ -310,6 +315,7 @@ export function useCustomSelection(
// 选中单个
function onSelect(record, checked) {
onSelectChild(record, checked);
updateSelected(record, checked);
emitChange();
}
@ -359,7 +365,25 @@ export function useCustomSelection(
}
// update-end--author:liaozhiyang---date:20231122---for【issues/5577】BasicTable组件全选和取消全选时不触发
}
// update-begin--author:liusq---date:20240819---for树形表格设置层级关联不生效
/**
*
* @param record
* @param checked
*/
function onSelectChild(record, checked) {
if (unref(propsRef)?.isTreeTable && unref(propsRef)?.rowSelection?.checkStrictly && !isRadio.value) {
if (record[childrenColumnName.value] && record[childrenColumnName.value].length > 0) {
record[childrenColumnName.value].forEach((children) => {
updateSelected(children, checked);
if (children[childrenColumnName.value] && children[childrenColumnName.value].length > 0) {
onSelectChild(children, checked);
}
});
}
}
}
// update-end--author:liusq---date:20240819---for树形表格设置层级关联不生效
// 用于判断是否是自定义选择列
function isCustomSelection(column: BasicColumn) {
return column.key === CUS_SEL_COLUMN_KEY;
@ -481,7 +505,7 @@ export function useCustomSelection(
// 清空所有选择
function clearSelectedRowKeys() {
onSelectAll(false);
onSelectAll(false, 'allPage');
}
// 通过 selectedKeys 同步 selectedRows
@ -536,28 +560,30 @@ export function useCustomSelection(
return false;
}
/**
*2023-11-22
*2024-08-08
*
*
*(使clearSelectedRowKeys())
*/
function getInvertRows(rows: any): any {
const allRows = findNodeAll(toRaw(unref(flattedData)), () => true, {
children: propsRef.value.childrenColumnName ?? 'children',
});
if (rows.length === 0 || rows.length === allRows.length) {
return allRows;
} else {
const allRowsKey = allRows.map((item) => getRecordKey(item));
rows.forEach((rItem) => {
const rItemKey = getRecordKey(rItem);
const findIndex = allRowsKey.findIndex((item) => rItemKey === item);
if (findIndex != -1) {
allRowsKey.splice(findIndex, 1);
allRows.splice(findIndex, 1);
function getInvertRows(selectedRows: any, checked: boolean, flag): any {
if (flag == 'currentPage') {
const curPageRows = findNodeAll(toRaw(unref(flattedData)), () => true, {
children: propsRef.value.childrenColumnName ?? 'children',
});
const selectedkeys = selectedRows.map((item) => getRecordKey(item));
const result: any = [];
curPageRows.forEach((item) => {
const curRowkey = getRecordKey(item);
const index = selectedkeys.findIndex((item) => item === curRowkey);
if (index == -1) {
checked && result.push(toRaw(item));
} else {
!checked && result.push(toRaw(item));
}
});
return result;
} else {
return toRaw(selectedRows);
}
return allRows;
}
function getSelectRows<T = Recordable>() {
return unref(selectedRows) as T[];

View File

@ -426,6 +426,9 @@ export interface BasicColumn extends ColumnProps<Recordable> {
//
flag?: 'INDEX' | 'DEFAULT' | 'CHECKBOX' | 'RADIO' | 'ACTION';
// update-begin--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
title: string | Fn;
// update-end--author:liaozhiyang---date:20240724---forissues/6908BasicColumnFormSchema
customTitle?: VueNode;
slots?: Recordable;
@ -465,6 +468,8 @@ export interface BasicColumn extends ColumnProps<Recordable> {
column: BasicColumn;
}) => any | VNodeChild | JSX.Element;
// update-end--author:liaozhiyang---date:20240425---forpull/1201antdTableSummarysummary
//
extraProps?: Recordable;
}
export type ColumnChangeParam = {

View File

@ -29,4 +29,5 @@ export interface PopConfirm {
icon?: string;
placement?: string;
overlayClassName?: string;
getPopupContainer: Fn;
}

View File

@ -5,7 +5,6 @@
<ImgUpload
:fullscreen="fullscreen"
@uploading="handleImageUploading"
@loading="handleLoading"
@done="handleDone"
v-show="editorRef"
:disabled="disabled"
@ -14,7 +13,6 @@
<!-- update-end--author:liaozhiyang---date:20240517---forTV360X-35富文本图片上传遮挡其他按钮 -->
<Editor :id="tinymceId" ref="elRef" :disabled="disabled" :init="initOptions" :style="{ visibility: 'hidden' }" v-if="!initOptions.inline"></Editor>
<slot v-else></slot>
<ProcessMask ref="processMaskRef" :show="showUploadMask"/>
</div>
</template>
@ -35,7 +33,6 @@
import 'tinymce/plugins/image';
import { defineComponent, computed, nextTick, ref, unref, watch, onDeactivated, onBeforeUnmount, onMounted } from 'vue';
import ImgUpload from './ImgUpload.vue';
import ProcessMask from './ProcessMask.vue';
import {simpleToolbar, menubar, simplePlugins} from './tinymce';
import { buildShortUUID } from '/@/utils/uuid';
import { bindHandlers } from './helper';
@ -85,10 +82,6 @@
type: Boolean,
default: true,
},
showUploadMask: {
type: Boolean,
default: false,
},
//
autoFocus:{
type: Boolean,
@ -98,9 +91,9 @@
export default defineComponent({
name: 'Tinymce',
components: { ImgUpload,Editor,ProcessMask },
components: { ImgUpload,Editor },
inheritAttrs: false,
props: tinymceProps as any,
props: tinymceProps,
emits: ['change', 'update:modelValue', 'inited', 'init-error'],
setup(props, { emit, attrs }) {
console.log("---Tinymce---初始化---")
@ -110,7 +103,6 @@
const tinymceId = ref<string>(buildShortUUID('tiny-vue'));
const elRef = ref<Nullable<HTMLElement>>(null);
const editorRootRef = ref<Nullable<HTMLElement>>(null);
const processMaskRef = ref<any>(null);
const imgUploadShow = ref(false);
const targetElem = ref<null | HTMLDivElement>(null);
@ -333,20 +325,6 @@
setValue(editor, val);
}
/**
* 上传进度计算
* @param file
* @param fileList
*/
function handleLoading(fileLength,showMask){
if(fileLength && fileLength > 0){
setTimeout(() => {
props?.showUploadMask && processMaskRef.value.calcProcess(fileLength)
},100)
}else{
props?.showUploadMask && (processMaskRef.value.showMask = showMask);
}
}
function getUploadingImgName(name: string) {
return `[uploading:${name}]`;
}
@ -419,9 +397,6 @@
editorRootRef,
imgUploadShow,
targetElem,
handleLoading,
processMaskRef
};
},
});
@ -453,7 +428,6 @@
}
// update-end--author:liaozhiyang---date:20240527---forTV360X-329
}
html[data-theme='dark'] {
.@{prefix-cls} {
.tox .tox-edit-area__iframe {background-color: #141414;}

View File

@ -8,7 +8,6 @@
:showUploadList="false"
:data="getBizData()"
:headers="getheader()"
:before-upload="beforeUpload"
accept=".jpg,.jpeg,.gif,.png,.webp"
>
<a-button type="primary" v-bind="{ ...getButtonProps }">
@ -38,8 +37,10 @@
default: false,
},
},
emits: ['uploading', 'done', 'error', 'loading'],
emits: ['uploading', 'done', 'error'],
setup(props, { emit }) {
let uploading = false;
//update-begin-author:taoyan date:2022-5-13 for:
function getheader() {
return getHeaders();
@ -66,37 +67,33 @@
};
});
let uploadLength = 0;
function handleChange({ file, fileList }) {
//
fileList = fileList.filter((file) => {
const existFile = uploadFileList.value.find(({ uid }) => uid === file.uid);
return existFile ? false : true;
});
uploadLength == 0 && (uploadLength = fileList.length);
if (file.status != 'uploading') {
emit('loading', uploadLength, true);
if (file.status === 'error') {
emit('error');
uploading = false;
}
//
let files = [] as any;
let noUploadingFileCount = 0;
if (file.status != 'uploading') {
fileList.forEach((file) => {
if (file.status === 'done' && file.response.success) {
const name = file?.name;
let realUrl = getFileAccessHttpUrl(file.response.message);
uploadFileList.value.push(file);
emit('done', name, realUrl);
files.push(file);
}
if (file.status != 'uploading') {
noUploadingFileCount++;
}
});
}
if (noUploadingFileCount == fileList.length) {
fileList.forEach((file) => {
const name = file?.name;
let realUrl = getFileAccessHttpUrl(file.response.message);
emit('done', name, realUrl);
});
}
}
//
function beforeUpload() {
uploadLength = 0;
emit('loading', null, true);
setTimeout(() => {
emit('loading', null, false);
}, 10000);
}
return {
prefixCls,
handleChange,
@ -105,8 +102,7 @@
getBizData,
t,
getButtonProps,
uploadFileList,
beforeUpload,
uploadFileList
};
},
});

View File

@ -1,99 +0,0 @@
<template>
<div class="mask" v-if="showMask && show">
<div class="progress-bar-rear">
<div class="progress-bar-front" :style="{ width: progressBarWidth }"></div>
</div>
<div class="value">{{ percentage }}</div>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
const props = defineProps({
backColor: {
type: [String],
default: 'white',
},
processColor: {
type: String,
default: '#018FFB',
},
show: {
type: Boolean,
default: false,
},
});
//
const showMask = ref(false);
//
const progressValue = ref<any>(0);
//
const currentNum = ref(0);
//
const progressBarWidth = computed(() => {
return progressValue.value > 0 ? `${progressValue.value}px` : '0px';
});
//
const percentage = computed(() => {
return `${progressValue.value}%`;
});
//
const frontColor = computed(() => {
return props.processColor;
});
//
const rearColor = computed(() => {
return props.backColor;
});
function calcProcess(totalNum) {
!showMask.value && (showMask.value = true);
currentNum.value += 1;
progressValue.value = ((currentNum.value / totalNum) * 100).toFixed(2);
console.log('currentNum.value', currentNum.value);
console.log('totalNum.value', totalNum);
if (currentNum.value == totalNum) {
showMask.value = false;
currentNum.value = 0;
progressValue.value = 0;
}
}
defineExpose({
calcProcess,
showMask,
});
</script>
<style lang="less">
.mask {
position: absolute; /* 或者使用固定定位等其他方式 */
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5); /* 半透明遮罩 */
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
z-index: 99;
}
.progress-bar-rear {
width: 100px; /* 进度条宽度 */
height: 10px; /* 进度条高度 */
background-color: v-bind(rearColor); /* 进度条颜色 */
border-radius: 4px;
}
.progress-bar-front {
height: 10px; /* 进度条高度 */
background-color: v-bind(frontColor); /* 进度条颜色 */
border-radius: 4px;
}
.value {
color: #fff;
margin-left: 5px;
font-size: 16px;
font-weight: 600;
}
</style>

View File

@ -201,7 +201,7 @@
//
async function handleStartUpload() {
const { maxNumber } = props;
if ((fileListRef.value.length + props.previewFileList?.length ?? 0) > maxNumber) {
if ((fileListRef.value.length + (props.previewFileList?.length ?? 0)) > maxNumber) {
return createMessage.warning(t('component.upload.maxNumber', [maxNumber]));
}
try {

View File

@ -158,6 +158,7 @@
import '../style/style.less';
const props = defineProps(['chatData', 'uuid', 'dataSource']);
const emit = defineEmits(['save']);
const { scrollRef, scrollToBottom, scrollToBottomIfAtBottom } = useScroll();
const prompt = ref<string>('');
const loading = ref<boolean>(false);
@ -335,6 +336,7 @@
try {
return await new Promise<void>((resolve) => {
props.chatData.length = 0;
emit('save');
resolve();
});
} catch {

View File

@ -102,6 +102,7 @@
<script setup lang="ts">
import { ref, watch } from 'vue';
const props = defineProps(['dataSource']);
const emit = defineEmits(['save']);
const inputRef = ref(null);
let inputValue = '';
//
@ -161,6 +162,7 @@
//
props.dataSource.active = null;
}
emit('save');
}
};
watch(

View File

@ -3,7 +3,7 @@
<template v-if="dataSource">
<div class="leftArea" :class="[expand ? 'expand' : 'shrink']">
<div class="content">
<slide v-if="uuid" :dataSource="dataSource"></slide>
<slide v-if="uuid" :dataSource="dataSource" @save="handleSave"></slide>
</div>
<div class="toggle-btn" @click="handleToggle">
<span class="icon">
@ -17,7 +17,7 @@
</div>
</div>
<div class="rightArea" :class="[expand ? 'expand' : 'shrink']">
<chat v-if="uuid && chatVisible" :uuid="uuid" :chatData="chatData" :dataSource="dataSource"></chat>
<chat v-if="uuid && chatVisible" :uuid="uuid" :chatData="chatData" :dataSource="dataSource" @save="handleSave"></chat>
</div>
</template>
<Spin v-else :spinning="true"></Spin>
@ -84,6 +84,14 @@
const save = (content) => {
defHttp.post({ url: configUrl.save, params: { content: JSON.stringify(content) } }, { isTransformResponse: false });
};
const handleSave = () => {
//
save(dataSource.value);
setTimeout(() => {
// watchwatch
clearTimeout(timer);
}, 50);
};
// dataSource
const execute = () => {
unwatch01 = watch(

View File

@ -5,15 +5,15 @@
<template #buttons>
<div :class="`${prefixCls}-button div`" :size="btnSize">
<slot v-if="showPrefix" name="toolbarPrefix" :size="btnSize" />
<a-button v-if="showAdd" type="primary" preIcon="ant-design:plus-outlined" :disabled="disabled" @click="trigger('add')">
<a-button v-if="showAdd" type="primary" preIcon="ant-design:plus-outlined" :disabled="disabled" :loading="deleting" @click="trigger('add')">
<span>新增</span>
</a-button>
<a-button v-if="showSave" preIcon="ant-design:save-outlined" :disabled="disabled" @click="trigger('save')">
<span>保存</span>
</a-button>
<template v-if="selectedRowIds.length > 0">
<Popconfirm v-if="showRemove" :title="`确定要删除这 ${selectedRowIds.length} 项吗?`" @confirm="trigger('remove')">
<a-button preIcon="ant-design:minus-outlined" :disabled="disabled">删除</a-button>
<template v-if="deleting || selectedRowIds.length > 0">
<Popconfirm v-if="showRemove" :title="`确定要删除这 ${selectedRowIds.length} 项吗?`" :disabled="deleting" @confirm="onRemove">
<a-button preIcon="ant-design:minus-outlined" :disabled="disabled" :loading="deleting">删除</a-button>
</Popconfirm>
<template v-if="showClearSelection">
<a-button preIcon="ant-design:delete-outlined" @click="trigger('clearSelection')">清空选择</a-button>
@ -115,4 +115,19 @@
function toggleCollapse() {
collapsed.value = !collapsed.value;
}
// TV360X-1975Onlineloading
const deleting = ref(false);
let deleteTimer: any = null
function onRemove() {
trigger('remove')
deleting.value = true;
if (deleteTimer) {
clearTimeout(deleteTimer)
}
deleteTimer = setTimeout(() => deleting.value = false, 300);
}
</script>

View File

@ -183,7 +183,9 @@ function handleSeqColumn({ props, col, columns }: HandleArgs) {
*/
function handleSelectionColumn({ props, data, col, columns }: HandleArgs) {
//
if (props.rowSelection) {
// -update-begin--author:liaozhiyang---date:20240617---forTV360X-1002checkbox
if (props.rowSelection && props.disabled == false) {
// -update-end--author:liaozhiyang---date:20240617---forTV360X-1002checkbox
let width = 45;
if (data.statistics.has && !props.rowExpand && !props.dragSort) {
width = 60;

View File

@ -1,6 +1,7 @@
import { onMounted, onUnmounted, nextTick } from 'vue';
import { JVxeTableMethods, JVxeTableProps } from '/@/components/jeecg/JVxeTable/src/types';
import Sortable from 'sortablejs';
import { isEnabledVirtualYScroll } from '/@/components/jeecg/JVxeTable/utils';
export function useDragSort(props: JVxeTableProps, methods: JVxeTableMethods) {
if (props.dragSort) {
@ -37,40 +38,73 @@ export function useDragSort(props: JVxeTableProps, methods: JVxeTableMethods) {
// @ts-ignore
startChildren = [...from.children];
},
onEnd(e) {
let oldIndex = e.oldIndex as number;
let newIndex = e.newIndex as number;
if (oldIndex === newIndex) {
return;
}
// VUEN-2505
let rowNode = xTable.getRowNode(e.item);
if (!rowNode) {
return;
}
let from = e.from;
let element = startChildren[oldIndex];
let target = null;
if (oldIndex > newIndex) {
//
if (oldIndex + 1 < startChildren.length) {
target = startChildren[oldIndex + 1];
onEnd(e: any) {
// -update-begin--author:liaozhiyang---date:20240619---forTV360X-585使
const isRealEnabledVirtual = isEnabledVirtualYScroll(props, xTable);
let newIndex;
let oldIndex;
// (loadData)
if (isRealEnabledVirtual) {
// e.clone()
const dragNode = e.clone;
const dragRowInfo = xTable.getRowNode(dragNode);
// e.item()
const itemNode = e.item;
const itemRowInfo = xTable.getRowNode(itemNode);
// e.newIndex()e.oldIndex ()
if (dragRowInfo!.rowid === itemRowInfo!.rowid) {
// e.clonee.itemDOMremove
if (e.newIndex === e.oldIndex) {
// index
return;
}
} else {
}
// DOM()
oldIndex = dragRowInfo!.index;
const len = e.from.childNodes.length;
let referenceIndex;
let referenceNode;
if (e.newIndex + 1 < len) {
// DOM
referenceNode = e.from.childNodes[e.newIndex + 1];
referenceIndex = xTable.getRowNode(referenceNode)!.index;
if (oldIndex > referenceIndex) {
newIndex = referenceIndex;
} else {
newIndex = referenceIndex - 1;
}
} else {
// DOM
referenceNode = e.from.childNodes[e.newIndex - 1];
referenceIndex = xTable.getRowNode(referenceNode)!.index;
newIndex = referenceIndex;
}
} else {
//
target = startChildren[oldIndex + 1];
}
from.removeChild(element);
from.insertBefore(element, target);
nextTick(() => {
// VUEN-2505
let diffIndex = rowNode!.index - oldIndex;
if (diffIndex > 0) {
oldIndex = oldIndex + diffIndex;
newIndex = newIndex + diffIndex;
oldIndex = e.oldIndex;
newIndex = e.newIndex;
if (oldIndex === newIndex) {
return;
}
const from = e.from;
const element = startChildren[oldIndex];
let target = null;
if (oldIndex > newIndex) {
//
if (oldIndex + 1 < startChildren.length) {
target = startChildren[oldIndex + 1];
}
} else {
//
target = startChildren[oldIndex + 1];
}
from.removeChild(element);
from.insertBefore(element, target);
}
// -update-end--author:liaozhiyang---date:20240620---forTV360X-585使
nextTick(() => {
methods.doSort(oldIndex, newIndex);
methods.trigger('dragged', { oldIndex, newIndex });
methods.trigger('dragged', { oldIndex: oldIndex, newIndex: newIndex });
});
},
});

View File

@ -11,6 +11,7 @@ import { useWebSocket } from './useWebSocket';
import { getPrefix, getJVxeAuths } from '../utils/authUtils';
import { excludeKeywords } from '../componentMap';
import { useColumnsCache } from './useColumnsCache';
import { isEnabledVirtualYScroll } from '/@/components/jeecg/JVxeTable/utils';
export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps, refs: JVxeRefs, instanceRef: Ref) {
let xTableTemp: VxeTableInstance & VxeTablePrivateMethods;
@ -195,7 +196,9 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
return getEnhanced(column.params.type).aopEvents.activeMethod!.apply(instanceRef.value, arguments as any) ?? true;
})();
if (!flag) {
getXTable().clearActived();
// -update-begin--author:liaozhiyang---date:20240619---forTV360X-1404vxetable
getXTable().clearEdit();
// -update-end--author:liaozhiyang---date:20240619---forTV360X-1404vxetable
}
return flag;
}
@ -424,8 +427,10 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
//
let result = await xTable.insertAt(rows, index);
if (setActive) {
// -update-begin--author:liaozhiyang---date:20240619---forTV360X-1404vxetable
//
xTable.setActiveRow(result.rows[result.rows.length - 1]);
xTable.setEditRow(result.rows[result.rows.length - 1]);
// -update-end--author:liaozhiyang---date:20240619---forTV360X-1404vxetable
}
await recalcSortNumber();
return result;
@ -453,8 +458,14 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
callback('', tableData);
}
type getTableDataOptions = {
rowIds?: string[];
// id
keepNewId?: boolean;
}
/** 获取表格数据 */
function getTableData(options: any = {}) {
function getTableData(options: getTableDataOptions = {}) {
let { rowIds } = options;
let tableData;
// id
@ -470,7 +481,10 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
//
tableData = getXTable().getTableData().fullData;
}
return filterNewRows(tableData, false);
return filterNewRows(tableData, {
keepNewId: options.keepNewId ?? false,
removeNewLine: false,
});
}
/** 仅获取新增的数据 */
@ -513,23 +527,33 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
return null;
}
type filterNewRowsOptions = {
keepNewId?: boolean;
removeNewLine?: boolean;
} | boolean
/**
* 过滤添加的行
* @param rows 要筛选的行数据
* @param remove true = 删除新增false=只删除id
* @param optOrRm 如果传 boolean 则是 removeNewLine 参数true = 删除新增false=只删除id如果传对象则是配置参数
* @param handler function
*/
function filterNewRows(rows, remove = true, handler?: Fn) {
function filterNewRows(rows, optOrRm:filterNewRowsOptions = true, handler?: Fn) {
let insertRecords = getXTable().getInsertRecords();
let records: Recordable[] = [];
optOrRm = typeof optOrRm === 'boolean' ? { removeNewLine: optOrRm } : optOrRm;
// true = false=id
let removeNewLine = optOrRm?.removeNewLine ?? true;
for (let row of rows) {
let item = cloneDeep(row);
if (insertRecords.includes(row)) {
handler ? handler({ item, row, insertRecords }) : null;
if (remove) {
if (removeNewLine) {
continue;
}
delete item.id;
if (!optOrRm?.keepNewId) {
delete item.id;
}
}
records.push(item);
}
@ -762,6 +786,11 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
if (xTable.keepSource) {
sort(xTable.internalData.tableSourceData);
}
// -update-begin--author:liaozhiyang---date:20240620---forTV360X-585使
if (isEnabledVirtualYScroll(props, xTable)) {
await xTable.loadData(xTable.internalData.tableFullData);
}
// -update-end--author:liaozhiyang---date:20240620---forTV360X-585使
return await recalcSortNumber(force);
}
}

View File

@ -107,3 +107,26 @@ export function vModel(value, row, column: Ref<any> | string) {
let property = isRef(column) ? column.value.property : column;
unref(row)[property] = value;
}
/**
* liaozhiyang
* 2024-06-20
* 判断当前行编辑是否使用了虚拟滚动并不是开启了就是还得满足数据数量大于gt值
*/
export function isEnabledVirtualYScroll(props, xTable): boolean {
let isRealEnabledVirtual = false;
const isEnabledVScroll = props?.scrollY?.enabled;
// 100
const gtYNum = props?.scrollY?.gt || 100;
if (isEnabledVScroll) {
const tableFullData = xTable.internalData.tableFullData;
if (gtYNum === 0) {
isRealEnabledVirtual = true;
} else {
if (tableFullData.length > gtYNum) {
isRealEnabledVirtual = true;
}
}
}
return isRealEnabledVirtual;
}

View File

@ -48,6 +48,12 @@
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
</template>
<template #bodyCell="{ text, column }">
<template v-if="column.fieldType === 'Image'">
<span v-if="!text" style="font-size: 12px; font-style: italic">无图片</span>
<img v-else :src="getImgView(text)" alt="图片不存在" class="cellIamge" @click="viewOnlineCellImage($event, text)" />
</template>
</template>
</BasicTable>
<!-- 跳转Href的动态组件方式 -->
@ -64,7 +70,9 @@
import { usePopBiz } from '/@/components/jeecg/OnLine/hooks/usePopBiz';
import { useMessage } from '/@/hooks/web/useMessage';
import { useRoute } from 'vue-router';
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
import { createImgPreview } from '/@/components/Preview/index';
export default defineComponent({
name: 'JPopupOnlReport',
components: {
@ -198,6 +206,40 @@
loadData(1);
}
/**
* 2024-07-24
* liaozhiyang
* TV360X-1756报表添加图片类型
* 图片
* @param text
*/
function getImgView(text) {
if (text && text.indexOf(',') > 0) {
text = text.substring(0, text.indexOf(','));
}
return getFileAccessHttpUrl(text);
}
/**
* 2024-07-24
* liaozhiyang
* TV360X-1756报表添加图片类型
* 预览列表 cell 图片
* @param text
*/
function viewOnlineCellImage(e, text) {
e.stopPropagation();
if (text) {
let imgList: any = [];
let arr = text.split(',');
for (let str of arr) {
if (str) {
imgList.push(getFileAccessHttpUrl(str));
}
}
createImgPreview({ imageList: imgList });
}
}
return {
attrs,
@ -229,6 +271,8 @@
searchQuery,
searchReset,
onExportXls,
getImgView,
viewOnlineCellImage,
};
},
});
@ -251,4 +295,12 @@
:deep(.ant-select-selector){
min-width: 95px;
}
.cellIamge {
height: 25px !important;
margin: 0 auto;
max-width: 80px;
font-size: 12px;
font-style: italic;
cursor: pointer;
}
</style>

View File

@ -9,6 +9,7 @@ import { useRouter, useRoute } from 'vue-router';
import { useMethods } from '/@/hooks/system/useMethods';
import { importViewsFile, _eval } from '/@/utils';
import {getToken} from "@/utils/auth";
import {replaceUserInfoByExpression} from "@/utils/common/compUtils";
export function usePopBiz(ob, tableRef?) {
// update-begin--author:liaozhiyang---date:20230811---forissues/675Popup
@ -188,7 +189,8 @@ export function usePopBiz(ob, tableRef?) {
* 加载列信息
*/
function loadColumnsInfo() {
let url = `${configUrl.getColumns}${props.code}`;
const {code} = handleCodeParams(true)
let url = `${configUrl.getColumns}${code}`;
//key
let groupIdKey = props.groupId ? `${props.groupId}${url}` : '';
httpGroupRequest(() => defHttp.get({ url }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {
@ -240,6 +242,11 @@ export function usePopBiz(ob, tableRef?) {
// isTotal
pagination.isTotal = '';
let url = `${configUrl.getColumnsAndData}${props.id}`;
const {query} = handleCodeParams()
if (query) {
url = url + query
}
//key
let groupIdKey = props.groupId ? `${props.groupId}${url}` : '';
httpGroupRequest(() => defHttp.get({ url }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {
@ -281,6 +288,39 @@ export function usePopBiz(ob, tableRef?) {
});
}
//
function handleCodeParams(onlyCode: boolean = false) {
if (!props.code) {
return {code: '', query: ''}
}
const firstIndex = props.code.indexOf('?')
if (firstIndex === -1) {
return {code: props.code, query: ''}
}
const code = props.code.substring(0, firstIndex)
if (onlyCode) {
return {code: code, query: ''}
}
const queryOrigin = props.code.substring(firstIndex, props.code.length);
let query: string
//
query = replaceUserInfoByExpression(queryOrigin)
//
if (typeof props.getFormValues === 'function') {
const values = props.getFormValues()
// ${xxx}
query = query.replace(/\${([^}]+)}/g, (_$0, $1) => {
if (values[$1] == null) {
return ''
}
return values[$1]
});
}
return {code, query, queryOrigin}
}
/**
* 处理求和的列 合计逻辑 [待优化 3.0]
*/
@ -502,10 +542,15 @@ export function usePopBiz(ob, tableRef?) {
// VUEN-1568
let keys = unref(checkedKeys);
if (keys.length > 0) {
params['force_id'] = keys
keys = keys
.map((i) => selectRows.value.find((item) => combineRowKey(item) === i)?.id)
.filter((i) => i != null && i !== '')
.join(',');
.filter((i) => i != null && i !== '');
// ID
if (keys.length === 0) {
createMessage.warning('由于数据中缺少ID字段故无法使用选中导出功能');
return;
}
params['force_id'] = keys.join(',');
}
handleExportXls(title.value, url, params);
}
@ -592,6 +637,10 @@ export function usePopBiz(ob, tableRef?) {
// update-begin--author:liaozhiyang---date:20240603---forTV360X-578onlineSQL
let url = `${configUrl.getColumnsAndData}${unref(cgRpConfigId)}`;
// update-end--author:liaozhiyang---date:20240603---forTV360X-578onlineSQL
const {query} = handleCodeParams()
if (query) {
url = url + query
}
//key
let groupIdKey = props.groupId ? `${props.groupId}${url}${JSON.stringify(params)}` : '';
httpGroupRequest(() => defHttp.get({ url, params }, { isTransformResponse: false, successMessageMode: 'none' }), groupIdKey).then((res) => {

View File

@ -87,6 +87,7 @@
HistoryFileList,
},
props: {
tableId: propTypes.string.def(''),
tableName: propTypes.string.def(''),
dataId: propTypes.string.def(''),
datetime: propTypes.number.def(1)
@ -146,14 +147,15 @@
function onSelectFileOk(temp) {
// update-begin--author:liaozhiyang---date:20240603---forTV360X-935
if (temp.id === '') return;
if (temp.length === 0) return;
// update-end--author:liaozhiyang---date:20240603---forTV360X-935
let arr = selectFileList.value;
arr.push({
...temp,
exist: true
})
selectFileList.value = arr;
// -update-begin--author:liaozhiyang---date:20240614---forTV360X-938
temp.forEach((item) => {
item.exist = true;
});
selectFileList.value = [...arr, ...temp];
// -update-end--author:liaozhiyang---date:20240614---forTV360X-938
}
return {

View File

@ -17,7 +17,7 @@
<span>{{ item.toUserId_dictText }}</span>
<Tooltip class="comment-last-content" @openChange="(v)=>visibleChange(v, item)">
<template #title>
<div v-html="getHtml(item.commentId_dictText)"></div>
<div v-html="getHtml(lineFeed(item.commentId_dictText))"></div>
</template>
<message-outlined />
</Tooltip>
@ -42,7 +42,7 @@
</template>
<template #content>
<div class="content" v-html="getHtml(item.commentContent)" style="font-size: 15px">
<div class="content" v-html="getHtml(lineFeed(item.commentContent))" style="font-size: 15px">
</div>
<div v-if="item.fileList && item.fileList.length > 0">
@ -105,6 +105,7 @@
HistoryFileList,
},
props: {
tableId: propTypes.string.def(''),
tableName: propTypes.string.def(''),
dataId: propTypes.string.def(''),
datetime: propTypes.number.def(1),
@ -281,6 +282,11 @@
}
}
}
// update-begin--author:liaozhiyang---date:20240618---forTV360X-932
const lineFeed = (content) => {
return content.replace(/\n/g, '<br>');
};
// update-end--author:liaozhiyang---date:20240618---forTV360X-932
return {
dataList,
@ -303,6 +309,7 @@
bottomCommentRef,
visibleChange,
listRef,
lineFeed,
};
},
});
@ -319,6 +326,9 @@
.ant-comment {
width: 100%;
}
:deep(.ant-comment-avatar) {
cursor: default;
}
}
.comment-author {
span {

View File

@ -2,10 +2,10 @@
<div class="comment-tabs-warp" v-if="showStatus">
<a-tabs v-if="show" @change="handleChange" :animated="false">
<a-tab-pane v-if="showComment" tab="评论" key="comment" class="comment-list-tab">
<comment-list :tableName="tableName" :dataId="dataId" :datetime="datetime1" :otherHeight="otherHeight"></comment-list>
<comment-list :tableId="tableId" :tableName="tableName" :dataId="dataId" :datetime="datetime1" :otherHeight="otherHeight"></comment-list>
</a-tab-pane>
<a-tab-pane v-if="showFiles" tab="文件" key="file">
<comment-files :tableName="tableName" :dataId="dataId" :datetime="datetime2"></comment-files>
<comment-files :tableId="tableId" :tableName="tableName" :dataId="dataId" :datetime="datetime2"></comment-files>
</a-tab-pane>
<a-tab-pane v-if="showDataLog" tab="日志" key="log">
<data-log-list :tableName="tableName" :dataId="dataId" :datetime="datetime3"></data-log-list>
@ -33,6 +33,7 @@
DataLogList,
},
props: {
tableId: propTypes.string.def(''),
tableName: propTypes.string.def(''),
dataId: propTypes.string.def(''),
//

View File

@ -1,7 +1,7 @@
<template>
<div :class="{'comment-active': commentActive}" class="comment-main" @click="handleClickBlank">
<textarea ref="commentRef" v-model="myComment" @keyup.enter="sendComment" @input="handleCommentChange" @blur="handleBlur" class="comment-content" :rows="3" placeholder="请输入你的评论,可以@成员" />
<div class="comment-content comment-html-shower" :class="{'no-content':noConent, 'top-div': showHtml, 'bottom-div': showHtml == false }" v-html="commentHtml" @click="handleClickHtmlShower"></div>
<textarea ref="commentRef" v-model="myComment" @keyup.enter="sendComment" @input="handleCommentChange" @blur="handleBlur" class="comment-content" :rows="3" placeholder="请输入你的评论,可以@成员"></textarea>
<div ref="commentContentRef" class="comment-content comment-html-shower" :class="{'no-content':noConent, 'top-div': showHtml, 'bottom-div': showHtml == false }" v-html="commentHtml" @click="handleClickHtmlShower"></div>
<div class="comment-buttons" v-if="commentActive">
<div style="cursor: pointer">
<Tooltip title="选择@用户">
@ -90,12 +90,18 @@
setup(props, { emit }) {
const uploadVisible = ref(false);
const uploadRef = ref();
const commentContentRef = ref<null | HTMLDivElement>(null);
//model
const [registerModal, { openModal, closeModal }] = useModal();
const buttonLoading = ref(false);
const myComment = ref<string>('');
function sendComment() {
console.log(myComment.value);
function sendComment(e) {
// update-begin--author:liaozhiyang---date:20240618---forTV360X-932
const keyCode = e.keyCode || e.which;
if (keyCode == 13 && e.shiftKey) {
return;
}
// update-end--author:liaozhiyang---date:20240618---forTV360X-932
let content = myComment.value;
if (!content && content !== '0') {
disabledButton.value = true;
@ -153,15 +159,29 @@
if (realname && username) {
let str = `${realname}[${username}]`;
let temp = myComment.value;
// update-begin--author:liaozhiyang---date:20240726---forTV360X-929@
if (!temp) {
myComment.value = '@' + str;
myComment.value = '@' + str + ' ';
} else {
if (temp.endsWith('@')) {
myComment.value = temp + str +' ';
const index = commentRef.value?.selectionStart ?? temp.length;
let startStr = temp.substring(0, index);
const endStr = temp.substring(index);
if (startStr.endsWith('@')) {
if (startStr.length >= 2) {
const i = startStr.length - 1;
const s_str = startStr.substring(0, i);
const e_str = startStr.substring(i);
const spacing = s_str.endsWith(' ') ? '' : ' ';
startStr = s_str + spacing + e_str;
}
myComment.value = startStr + str + ' ' + endStr;
} else {
myComment.value = '@' + str + ' ' + temp + ' ';
const _symbol = startStr && startStr.endsWith(' ') ? '@' : ' @';
myComment.value = startStr + _symbol + str + ' ' + endStr;
}
}
// update-begin--author:liaozhiyang---date:20240726---forTV360X-929@
//update-begin---author:wangshuai---date:2024-01-22---for:QQYUN-8002---
showHtml.value = false;
commentRef.value.focus();
@ -171,18 +191,22 @@
}
closeModal();
}
function handleCommentChange() {
//console.log(1,e)
}
watch(
() => myComment.value,
(val) => {
if (val && val.endsWith('@')) {
openSelectUser();
}
// update-begin--author:liaozhiyang---date:20240724---forTV360X-927@
function handleCommentChange(e) {
if (e.data === '@') {
e.target.blur();
openSelectUser();
}
);
}
// watch(
// () => myComment.value,
// (val) => {
// if (val && val.endsWith('@')) {
// openSelectUser();
// }
// }
// );
// update-end--author:liaozhiyang---date:20240724---forTV360X-927@
const emojiButton = ref();
function onSelectEmoji(emoji) {
@ -255,6 +279,11 @@
}
function handleBlur() {
showHtml.value = true;
// update-begin--author:liaozhiyang---date:20240724---for
setTimeout(() => {
commentContentRef.value!.scrollTop = commentRef.value.scrollTop;
}, 0);
// update-end--author:liaozhiyang---date:20240724---for
}
const commentActive = ref(false);
@ -306,7 +335,8 @@
commentActive,
noConent,
changeActive,
selectFirstFile
selectFirstFile,
commentContentRef,
};
},
};
@ -342,7 +372,9 @@
width: 100%;
border: solid 0px;
outline: none;
// update-begin--author:liaozhiyang---date:20240724---forTV360X-933
resize: none;
// update-end--author:liaozhiyang---date:20240724---forTV360X-933
.emoji-item {
display: inline-block !important;
width: 0 !important;
@ -361,7 +393,10 @@
position: absolute;
top: 0;
left: 0;
height: 70px;
// update-begin--author:liaozhiyang---date:20240724---for
height: 78px;
overflow-y: auto;
// update-end--author:liaozhiyang---date:20240724---for
&.bottom-div {
z-index: -99;
}

View File

@ -124,6 +124,7 @@ export function useCommentWithFile(props) {
async function saveComment(obj) {
const {fromUserId, toUserId, commentId, commentContent} = obj;
let commentData = {
tableId: props.tableId,
tableName: props.tableName,
tableDataId: props.dataId,
fromUserId,

View File

@ -49,6 +49,10 @@ export const APP__THEME__COLOR = '__APP__THEME__COLOR__';
//
export const ROLE_AUTH_CONFIG_KEY = 'ROLE__AUTH__CONFIG__KEY__';
//
export const DEPART_ROLE_AUTH_CONFIG_KEY = 'DEPART__ROLE__AUTH__CONFIG__KEY__';
//
export const DEPART_MANGE_AUTH_CONFIG_KEY = 'DEPART__MANGE__AUTH__CONFIG__KEY__';
export enum CacheTypeEnum {
SESSION,

View File

@ -70,6 +70,15 @@ export function useJvxeMethod(requestAddOrEdit, classifyIntoFormData, tableRefs,
//update-end-author:liusq date:2024-06-12 for: TV360X-478 tabtab
}
//update-end-author:taoyan date:2022-11-22 for: VUEN-2866Tab
//update-begin---author:wangshuai---date:2024-06-17---for:TV360X-1064---
if (e?.errorFields) {
const firstField = e.errorFields[0];
if (firstField) {
formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'end' });
}
}
return Promise.reject(e?.errorFields);
//update-end---author:wangshuai---date:2024-06-17---for:TV360X-1064---
} else {
console.error(e);
}

View File

@ -163,7 +163,9 @@ export function usePermission() {
return true;
}
} else {
return true;
// update-begin--author:liaozhiyang---date:20240705---forTV360X-1604
return false;
// update-end--author:liaozhiyang---date:20240705---forTV360X-1604
}
}
return false;

View File

@ -17,14 +17,13 @@ export function connectWebSocket(url: string) {
result = useWebSocket(url, {
// (10)
autoReconnect: {
retries: 10,
delay: 5000,
retries : 10,
delay : 5000
},
//
heartbeat: {
message: 'ping',
// 55
interval: 5000,
message: "ping",
interval: 55000
},
protocols: [token],
// update-begin--author:liaozhiyang---date:20240726---for[issues/6662] socket

View File

@ -357,7 +357,10 @@ export const useUserStore = defineStore({
try {
const { goHome = true, mode, ...ThirdLoginParams } = params;
const data = await thirdLogin(ThirdLoginParams, mode);
const { token } = data;
//update-begin---author:wangshuai---date:2024-07-01---for:issues/66520---
const { token, userInfo } = data;
this.setTenant(userInfo?.loginTenantId);
//update-end---author:wangshuai---date:2024-07-01---for:issues/66520---
// save token
this.setToken(token);
return this.afterLoginAction(goHome, data);

View File

@ -0,0 +1,38 @@
import {areaList} from '@vant/area-data'
import {freezeDeep} from "@/utils/common/compUtils";
//
export const pcaa = freezeDeep(usePlatPcaaData())
/**
* 获取扁平化的省市区数据
*/
function usePlatPcaaData() {
const {city_list: city, county_list: county, province_list: province} = areaList;
const dataMap = new Map<string, Recordable>()
const flatData: Recordable = {'86': province}
//
Object.keys(province).forEach((code) => {
flatData[code] = {}
dataMap.set(code.slice(0, 2), flatData[code])
})
//
Object.keys(city).forEach((code) => {
flatData[code] = {}
dataMap.set(code.slice(0, 4), flatData[code])
//
const getProvince = dataMap.get(code.slice(0, 2))
if (getProvince) {
getProvince[code] = city[code]
}
});
//
Object.keys(county).forEach((code) => {
//
const getCity = dataMap.get(code.slice(0, 4))
if (getCity) {
getCity[code] = county[code]
}
});
return flatData
}

View File

@ -5,6 +5,7 @@ import { FormSchema } from '/@/components/Form';
import { reactive } from "vue";
import { getTenantId, getToken } from "/@/utils/auth";
import { useUserStoreWithOut } from "/@/store/modules/user";
import dayjs from 'dayjs';
import { Modal } from "ant-design-vue";
import { defHttp } from "@/utils/http/axios";
@ -416,6 +417,14 @@ export function getUserInfoByExpression(expression) {
if (!expression) {
return expression;
}
//
if (expression === 'sys_date' || expression === 'sysDate') {
return dayjs().format('YYYY-MM-DD');
}
//
if (expression === 'sys_time' || expression === 'sysTime') {
return dayjs().format('HH:mm:ss');
}
const userStore = useUserStoreWithOut();
let userInfo = userStore.getUserInfo;
if (userInfo) {
@ -574,4 +583,23 @@ export function translateTitle(data) {
});
}
return data;
}
}
/**
*
* 深度冻结对象
* @param obj Object or Array
*/
export function freezeDeep(obj: Recordable | Recordable[]) {
if (obj != null) {
if (Array.isArray(obj)) {
obj.forEach(item => freezeDeep(item))
} else if (typeof obj === 'object') {
Object.values(obj).forEach(value => {
freezeDeep(value)
})
}
Object.freeze(obj)
}
return obj
}

View File

@ -30,8 +30,10 @@ export async function validateFormModelAndTables(validate, formData, cases, prop
//update-end---author:wangshuai ---date:20220507 for[VUEN-912]--------------
resolve(formData);
})
.catch(() => {
reject({ error: VALIDATE_FAILED, index: 0 });
//update-begin---author:wangshuai---date:2024-06-17---for:TV360X-1064---
.catch(({ errorFields }) => {
reject({ error: VALIDATE_FAILED, index: 0, errorFields: errorFields });
//update-end---author:wangshuai---date:2024-06-17---for:TV360X-1064---
});
});
Object.assign(dataMap, { formValue: values });

View File

@ -1,5 +1,6 @@
import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router';
import type { App, Plugin } from 'vue';
import type { FormSchema } from "@/components/Form";
import { unref } from 'vue';
import { isObject } from '/@/utils/is';
@ -60,6 +61,7 @@ export function openWindow(url: string, opt?: { target?: TargetContext | string;
export function getDynamicProps<T, U>(props: T): Partial<U> {
const ret: Recordable = {};
// @ts-ignore
Object.keys(props).map((key) => {
ret[key] = unref((props as Recordable)[key]);
});
@ -78,10 +80,24 @@ export function getValueType(props, field) {
let valueType = 'string';
if (formSchema) {
let schema = formSchema.filter((item) => item.field === field)[0];
valueType = schema.componentProps && schema.componentProps.valueType ? schema.componentProps.valueType : valueType;
valueType = schema && schema.componentProps && schema.componentProps.valueType ? schema.componentProps.valueType : valueType;
}
return valueType;
}
/**
* 获取表单字段值数据类型
* @param schema
*/
export function getValueTypeBySchema(schema: FormSchema) {
let valueType = 'string';
if (schema) {
const componentProps = schema.componentProps as Recordable;
valueType = componentProps?.valueType ? componentProps?.valueType : valueType;
}
return valueType;
}
export function getRawRoute(route: RouteLocationNormalized): RouteLocationNormalized {
if (!route) return route;
const { matched, ...opt } = route;
@ -110,6 +126,7 @@ export const withInstall = <T>(component: T, alias?: string) => {
const comp = component as any;
comp.install = (app: App) => {
// @ts-ignore
app.component(comp.name || comp.displayName, component);
if (alias) {
app.config.globalProperties[alias] = component;
@ -438,3 +455,98 @@ export const setPopContainer = (node, selector) => {
return selector;
}
};
/**
* 2024-06-14
* liaozhiyang
* 根据控件显示条件
* labelvalue通用titleval给权限管理用的
*/
export function useConditionFilter() {
//
const commonConditionOptions = [
{label: '为空', value: 'empty', val: 'EMPTY'},
{label: '不为空', value: 'not_empty', val: 'NOT_EMPTY'},
]
//
const numberConditionOptions = [
{ label: '等于', value: 'eq', val: '=' },
{ label: '在...中', value: 'in', val: 'IN', title: '包含' },
{ label: '不等于', value: 'ne', val: '!=' },
{ label: '大于', value: 'gt', val: '>' },
{ label: '大于等于', value: 'ge', val: '>=' },
{ label: '小于', value: 'lt', val: '<' },
{ label: '小于等于', value: 'le', val: '<=' },
...commonConditionOptions,
];
// markdown
const inputConditionOptions = [
{ label: '等于', value: 'eq', val: '=' },
{ label: '模糊', value: 'like', val: 'LIKE' },
{ label: '以..开始', value: 'right_like', title: '右模糊', val: 'RIGHT_LIKE' },
{ label: '以..结尾', value: 'left_like', title: '左模糊', val: 'LEFT_LIKE' },
{ label: '在...中', value: 'in', val: 'IN', title: '包含' },
{ label: '不等于', value: 'ne', val: '!=' },
...commonConditionOptions,
];
// popuppopupDict
const selectConditionOptions = [
{ label: '等于', value: 'eq', val: '=' },
{ label: '在...中', value: 'in', val: 'IN', title: '包含' },
{ label: '不等于', value: 'ne', val: '!=' },
...commonConditionOptions,
];
const def = [
{ label: '等于', value: 'eq', val: '=' },
{ label: '模糊', value: 'like', val: 'LIKE' },
{ label: '以..开始', value: 'right_like', title: '右模糊', val: 'RIGHT_LIKE' },
{ label: '以..结尾', value: 'left_like', title: '左模糊', val: 'LEFT_LIKE' },
{ label: '在...中', value: 'in', val: 'IN', title: '包含' },
{ label: '不等于', value: 'ne', val: '!=' },
{ label: '大于', value: 'gt', val: '>' },
{ label: '大于等于', value: 'ge', val: '>=' },
{ label: '小于', value: 'lt', val: '<' },
{ label: '小于等于', value: 'le', val: '<=' },
...commonConditionOptions,
];
const filterCondition = (data) => {
if (data.view == 'text' && data.fieldType == 'number') {
data.view = 'number';
}
switch (data.view) {
case 'text':
case 'textarea':
case 'umeditor':
case 'markdown':
case 'pca':
case 'popup':
return inputConditionOptions;
case 'list':
case 'radio':
case 'checkbox':
case 'switch':
case 'sel_user':
case 'sel_depart':
case 'link_table':
case 'popup_dict':
case 'list_multi':
case 'sel_search':
case 'cat_tree':
case 'sel_tree':
return selectConditionOptions;
case 'date':
// number
case 'number':
return numberConditionOptions;
default:
return def;
}
};
return { filterCondition };
}

View File

@ -788,34 +788,35 @@ export const schemas: FormSchema[] = [
componentProps: {
selectPlaceholder: '可选择系统变量',
inputPlaceholder: '请输入',
selectWidth:'200px',
options: [
{
label: '登录用户账号',
value: '${sys_user_code}',
value: '#{sys_user_code}',
},
{
label: '登录用户名称',
value: '${sys_user_name}',
value: '#{sys_user_name}',
},
{
label: '当前日期',
value: '${sys_date}',
value: '#{sys_date}',
},
{
label: '当前时间',
value: '${sys_date}',
value: '#{sys_time}',
},
{
label: '登录用户部门',
value: '${sys_org_code}',
value: '#{sys_org_code}',
},
{
label: '用户拥有部门',
value: '${sys_multi_org_code}',
value: '#{sys_multi_org_code}',
},
{
label: '登录用户租户',
value: '${tenant_id}',
value: '#{tenant_id}',
},
],
},

View File

@ -44,7 +44,9 @@
columns: columns,
formConfig: {
schemas: searchFormSchema,
fieldMapToTime: [['fieldTime', ['createTime_begin', 'createTime_end'], 'YYYY-MM-DD HH:mm:ss']],
//update-begin---author:wangshuai---date:2024-06-11---for:TV360X-545---
fieldMapToTime: [['sendTime', ['sendTimeBegin', 'sendTimeEnd'], 'YYYY-MM-DD']],
//update-end---author:wangshuai---date:2024-06-11---for:TV360X-545---
},
},
});

View File

@ -64,12 +64,21 @@ export const searchFormSchema: FormSchema[] = [
field: 'titile',
label: '标题',
component: 'Input',
colProps: { span: 8 },
colProps: { span: 6 },
},
{
field: 'sender',
label: '发布人',
component: 'Input',
colProps: { span: 8 },
colProps: { span: 6 },
},
{
field: 'sendTime',
label: '发布时间',
component: 'RangeDate',
componentProps: {
valueType: 'Date',
},
colProps: { span: 6 },
},
];

View File

@ -64,7 +64,7 @@
},
});
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
const [registerTable, { reload }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
/**
* 操作列定义
@ -172,6 +172,12 @@
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDeleteQuartz({ ids: selectedRowKeys.value }, reload);
await batchDeleteQuartz({ ids: selectedRowKeys.value }, () => {
// -update-begin--author:liaozhiyang---date:20240702---forTV360X-1662
reload();
selectedRows.value = [];
selectedRowKeys.value = [];
// -update-end--author:liaozhiyang---date:20240702---forTV360X-1662
});
}
</script>

View File

@ -0,0 +1,84 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="路由回收站" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable">
<template #status="{ record, text }">
<a-tag color="pink" v-if="text == 0">禁用</a-tag>
<a-tag color="#87d068" v-if="text == 1">正常</a-tag>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { BasicTable, useTable, TableAction } from '/@/components/Table';
import { columns } from '../route.data';
import { deleteRouteList, putRecycleBin, deleteRecycleBin } from '../route.api';
// Emits
const emit = defineEmits(['success', 'register']);
const checkedKeys = ref<Array<string | number>>([]);
const [registerModal] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const [registerTable, { reload }] = useTable({
rowKey: 'id',
api: deleteRouteList,
columns: columns,
striped: true,
useSearchForm: false,
bordered: true,
showIndexColumn: false,
pagination: false,
tableSetting: { fullScreen: true },
canResize: false,
actionColumn: {
width: 150,
title: '操作',
dataIndex: 'action',
slots: { customRender: 'action' },
fixed: 'right',
},
});
/**
* 还原事件
*/
async function handleRevert(record) {
await putRecycleBin({ ids: record.id }, reload);
emit('success');
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteRecycleBin({ ids: record.id }, reload);
}
//
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

@ -3,6 +3,7 @@
<BasicTable @register="registerTable" :indexColumnProps="indexColumnProps">
<template #tableTitle>
<a-button preIcon="ant-design:plus-outlined" type="primary" @click="handleAdd" style="margin-right: 5px">新增</a-button>
<a-button type="primary" @click="openRecycleModal(true)" preIcon="ant-design:hdd-outlined"> 回收站</a-button>
</template>
<template #status="{ record, text }">
<a-tag color="pink" v-if="text == 0">禁用</a-tag>
@ -13,22 +14,27 @@
</template>
</BasicTable>
<RouteModal @register="registerDrawer" @success="reload" />
<!--回收站弹窗-->
<RouteRecycleBinModal @register="registerRecycleModal" @success="reload" />
</div>
</template>
<script lang="ts" name="monitor-route" setup>
import { ref } from 'vue';
import { BasicTable, TableAction } from '/@/components/Table';
import { useModal } from '/@/components/Modal';
import { getRouteList, deleteRoute } from './route.api';
import { getRouteList, deleteRoute, copyRoute } from './route.api';
import { columns } from './route.data';
import RouteModal from './RouteModal.vue';
import { useMessage } from '/@/hooks/web/useMessage';
import { useDrawer } from '/@/components/Drawer';
import { useListPage } from '/@/hooks/system/useListPage';
import RouteRecycleBinModal from './components/RouteRecycleBinModal.vue';
const { createMessage } = useMessage();
const [registerDrawer, { openDrawer }] = useDrawer();
const checkedKeys = ref<Array<string | number>>([]);
//model
const [registerRecycleModal, { openModal: openRecycleModal }] = useModal();
//
const { prefixCls, tableContext } = useListPage({
designScope: 'router-template',
@ -59,6 +65,13 @@
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '复制',
popConfirm: {
title: '是否确认复制',
confirm: handleCopy.bind(null, record),
},
},
{
label: '删除',
popConfirm: {
@ -94,6 +107,13 @@
isUpdate: true,
});
}
/**
* 复制
*/
async function handleCopy(record) {
await copyRoute({ id: record.id }, reload);
createMessage.success('复制成功');
}
/**
* 删除事件

View File

@ -2,9 +2,14 @@ import { defHttp } from '/@/utils/http/axios';
enum Api {
list = '/sys/gatewayRoute/list',
deleteList = '/sys/gatewayRoute/deleteList',
save = '/sys/gatewayRoute/add',
edit = '/sys/gatewayRoute/updateAll',
delete = '/sys/gatewayRoute/delete',
copyRoute = '/sys/gatewayRoute/copyRoute',
batchPutRecycleBin = '/sys/gatewayRoute/putRecycleBin',
batchDeleteRecycleBin = '/sys/gatewayRoute/deleteRecycleBin',
}
/**
@ -14,6 +19,13 @@ enum Api {
export const getRouteList = (params) => {
return defHttp.get({ url: Api.list, params });
};
/**
* 查询逻辑删除的路由列表
* @param params
*/
export const deleteRouteList = (params) => {
return defHttp.get({ url: Api.deleteList, params });
};
/**
* 保存或者更新路由
@ -32,3 +44,30 @@ export const deleteRoute = (params, handleSuccess) => {
handleSuccess();
});
};
/**
* 回收站还原
* @param params
*/
export const putRecycleBin = (params, handleSuccess) => {
return defHttp.put({ url: Api.batchPutRecycleBin, params }).then(() => {
handleSuccess();
});
};
/**
* 回收站删除
* @param params
*/
export const deleteRecycleBin = (params, handleSuccess) => {
return defHttp.delete({ url: `${Api.batchDeleteRecycleBin}?ids=${params.ids}` }).then(() => {
handleSuccess();
});
};
/**
* 复制
*/
export const copyRoute = (params, handleSuccess) => {
return defHttp.get({ url: Api.copyRoute, params }).then(() => {
handleSuccess();
});
};

View File

@ -21,7 +21,7 @@ export const columns: BasicColumn[] = [
title: '状态',
dataIndex: 'status',
slots: { customRender: 'status' },
width: 200,
width: 150,
},
];

View File

@ -167,7 +167,7 @@
Modal.warning(options)
} else {
createMessage.warning({
content: "同步失败,请检查对接信息录入中是否填写正确,并确认是否已开启钉钉配置!",
content: res.message || "同步失败,请检查对接信息录入中是否填写正确,并确认是否已开启钉钉配置!",
duration: 5
});
}

View File

@ -18,13 +18,13 @@ export const searchFormSchema: FormSchema[] = [
{
label: '名称',
field: 'name',
component: 'Input',
component: 'JInput',
colProps: { span: 6 },
},
{
label: '编码',
field: 'code',
component: 'Input',
component: 'JInput',
colProps: { span: 6 },
},
];

View File

@ -323,7 +323,13 @@
}
function onExportXls() {
handleExportXls('部门信息', Api.exportXlsUrl);
//update-begin---author:wangshuai---date:2024-07-05---for:TV360X-1671---
let params = {}
if(checkedKeys.value && checkedKeys.value.length > 0) {
params['selections'] = checkedKeys.value.join(',')
}
handleExportXls('部门信息', Api.exportXlsUrl,params);
//update-end---author:wangshuai---date:2024-07-05---for:TV360X-1671---
}
defineExpose({

View File

@ -9,7 +9,7 @@
:checkedKeys="checkedKeys"
:selectedKeys="selectedKeys"
:expandedKeys="expandedKeys"
:checkStrictly="checkStrictly"
:checkStrictly="true"
style="height: 500px; overflow: auto"
@check="onCheck"
@expand="onExpand"
@ -28,10 +28,12 @@
<a-dropdown :trigger="['click']" placement="top">
<template #overlay>
<a-menu>
<a-menu-item key="3" @click="toggleCheckALL(true)">全部勾选</a-menu-item>
<a-menu-item key="4" @click="toggleCheckALL(false)">取消全选</a-menu-item>
<a-menu-item key="5" @click="toggleExpandAll(true)">展开所有</a-menu-item>
<a-menu-item key="6" @click="toggleExpandAll(false)">收起所有</a-menu-item>
<a-menu-item key="3" @click="toggleCheckALL(true)">{{ t('component.tree.selectAll') }}</a-menu-item>
<a-menu-item key="4" @click="toggleCheckALL(false)">{{ t('component.tree.unSelectAll') }}</a-menu-item>
<a-menu-item key="5" @click="toggleExpandAll(true)">{{ t('component.tree.expandAll') }}</a-menu-item>
<a-menu-item key="6" @click="toggleExpandAll(false)">{{ t('component.tree.unExpandAll') }}</a-menu-item>
<a-menu-item key="7" @click="toggleRelationAll(false)">{{ t('component.tree.checkStrictly') }}</a-menu-item>
<a-menu-item key="8" @click="toggleRelationAll(true)">{{ t('component.tree.checkUnStrictly') }}</a-menu-item>
</a-menu>
</template>
<a-button style="float: left">
@ -54,6 +56,8 @@
import { queryRoleTreeList, queryDepartPermission, saveDepartPermission } from '../depart.api';
import { useDesign } from '/@/hooks/web/useDesign';
import { translateTitle } from '/@/utils/common/compUtils';
import { DEPART_MANGE_AUTH_CONFIG_KEY } from '/@/enums/cacheEnum';
import { useI18n } from '/@/hooks/web/useI18n';
const { prefixCls } = useDesign('j-depart-form-content');
const props = defineProps({
@ -64,29 +68,47 @@
const basicTree = ref();
const loading = ref<boolean>(false);
//
const allTreeKeys = ref([]);
const treeData = ref<any[]>([]);
const expandedKeys = ref<Array<any>>([]);
const selectedKeys = ref<Array<any>>([]);
const checkedKeys = ref<Array<any>>([]);
const lastCheckedKeys = ref<Array<any>>([]);
const checkStrictly = ref(true);
const checkStrictly = ref(false);
const { t } = useI18n();
//
const [registerDataRuleDrawer, dataRuleDrawer] = useDrawer();
// onCreated
loadData();
loadData({
success: (ids) => {
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1689
const localData = localStorage.getItem(DEPART_MANGE_AUTH_CONFIG_KEY);
if (localData) {
const obj = JSON.parse(localData);
obj.level && toggleRelationAll(obj.level == 'relation' ? false : true);
obj.expand && toggleExpandAll(obj.expand == 'openAll' ? true :false);
} else {
// expandedKeys.value = ids;
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1689
}
});
watch(departId, () => loadDepartPermission(), { immediate: true });
async function loadData() {
async function loadData(options: any = {}) {
try {
loading.value = true;
let { treeList } = await queryRoleTreeList();
let { treeList, ids } = await queryRoleTreeList();
//update-begin---author:wangshuai---date:2024-04-08---for:issues/1169 t('') ---
treeData.value = translateTitle(treeList);
//update-end---author:wangshuai---date:2024-04-08---for:issues/1169 t('') ---
await nextTick();
toggleExpandAll(true);
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1689
allTreeKeys.value = ids;
options.success?.(ids);
// update-end--author:liaozhiyang---date:20240704---forTV360X-1689
} finally {
loading.value = false;
}
@ -120,14 +142,59 @@
}
}
// tree
function onCheck(event) {
if (!Array.isArray(event)) {
checkedKeys.value = event.checked;
/**
* 点击选中
* 2024-07-04
* liaozhiyang
*/
function onCheck(o, e) {
// checkStrictly: true=>false=>.
if (checkStrictly.value) {
checkedKeys.value = o.checked ? o.checked : o;
} else {
checkedKeys.value = event;
const keys = getNodeAllKey(e.node, 'children', 'key');
if (e.checked) {
// keysnew Set
checkedKeys.value = [...new Set([...checkedKeys.value, ...keys])];
} else {
const result = removeMatchingItems(checkedKeys.value, keys);
checkedKeys.value = result;
}
}
}
/**
* 2024-07-04
* liaozhiyang
* 删除相匹配数组的项
*/
function removeMatchingItems(arr1, arr2) {
// 使 arr2
const hashTable = {};
for (const item of arr2) {
hashTable[item] = true;
}
// 使 filter
return arr1.filter((item) => !hashTable[item]);
}
/**
* 2024-07-04
* liaozhiyang
* 获取当前节点及以下所有子孙级的key
*/
function getNodeAllKey(node: any, children: any, key: string) {
const result: any = [];
result.push(node[key]);
const recursion = (data) => {
data.forEach((item: any) => {
result.push(item[key]);
if (item[children]?.length) {
recursion(item[children]);
}
});
};
node[children]?.length && recursion(node[children]);
return result;
}
// tree
function onExpand($expandedKeys) {
@ -152,17 +219,50 @@
//
async function toggleExpandAll(flag) {
basicTree.value.expandAll(flag);
await nextTick();
expandedKeys.value = basicTree.value.getExpandedKeys();
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1689
if (flag) {
expandedKeys.value = allTreeKeys.value;
saveLocalOperation('expand', 'openAll');
} else {
expandedKeys.value = [];
saveLocalOperation('expand', 'closeAll');
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1689
}
//
async function toggleCheckALL(flag) {
basicTree.value.checkAll(flag);
await nextTick();
checkedKeys.value = basicTree.value.getCheckedKeys();
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1689
if (flag) {
checkedKeys.value = allTreeKeys.value;
} else {
checkedKeys.value = [];
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1689
}
// ()
const toggleRelationAll = (flag) => {
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1689
checkStrictly.value = flag;
if (flag) {
saveLocalOperation('level', 'standAlone');
} else {
saveLocalOperation('level', 'relation');
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1689
};
/**
* 2024-07-04
* liaozhiyang
* 缓存
* */
const saveLocalOperation = (key, value) => {
const localData = localStorage.getItem(DEPART_MANGE_AUTH_CONFIG_KEY);
const obj = localData ? JSON.parse(localData) : {};
obj[key] = value;
localStorage.setItem(DEPART_MANGE_AUTH_CONFIG_KEY, JSON.stringify(obj))
};
</script>
<style lang="less" scoped>

View File

@ -1,6 +1,5 @@
<template>
<BasicDrawer
title="部门角色权限配置"
:width="650"
:loading="loading"
showFooter
@ -9,18 +8,35 @@
@close="onClose"
@register="registerDrawer"
>
<template #title>
部门角色权限配置
<a-dropdown>
<Icon icon="ant-design:more-outlined" class="more-icon" />
<template #overlay>
<a-menu @click="treeMenuClick">
<a-menu-item key="checkAll">{{ t('component.tree.selectAll') }}</a-menu-item>
<a-menu-item key="cancelCheck">{{ t('component.tree.unSelectAll') }}</a-menu-item>
<div class="line"></div>
<a-menu-item key="openAll">{{ t('component.tree.expandAll') }}</a-menu-item>
<a-menu-item key="closeAll">{{ t('component.tree.unExpandAll') }}</a-menu-item>
<div class="line"></div>
<a-menu-item key="relation">{{ t('component.tree.checkStrictly') }}</a-menu-item>
<a-menu-item key="standAlone">{{ t('component.tree.checkUnStrictly') }}</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<div>
<a-spin :spinning="loading">
<template v-if="treeData.length > 0">
<BasicTree
title="所拥有的部门权限"
toolbar
checkable
:treeData="treeData"
:checkedKeys="checkedKeys"
:selectedKeys="selectedKeys"
:expandedKeys="expandedKeys"
:checkStrictly="checkStrictly"
:checkStrictly="true"
:clickRowToExpand="false"
@check="onCheck"
@expand="onExpand"
@ -49,10 +65,11 @@
import { BasicTree } from '/@/components/Tree/index';
import { BasicDrawer, useDrawer, useDrawerInner } from '/@/components/Drawer';
import { useMessage } from '/@/hooks/web/useMessage';
import { useI18n } from '/@/hooks/web/useI18n';
import DepartRoleDataRuleDrawer from './DepartRoleDataRuleDrawer.vue';
import { queryTreeListForDeptRole, queryDeptRolePermission, saveDeptRolePermission } from '../depart.user.api';
import { translateTitle } from "@/utils/common/compUtils";
import { DEPART_ROLE_AUTH_CONFIG_KEY } from '/@/enums/cacheEnum';
defineEmits(['register']);
const { createMessage } = useMessage();
@ -65,25 +82,42 @@
const expandedKeys = ref<Array<any>>([]);
const selectedKeys = ref<Array<any>>([]);
const allTreeKeys = ref<Array<any>>([]);
const checkStrictly = ref(true);
// truefalse
const checkStrictly = ref(false);
const { t } = useI18n();
//
const [registerDrawer, { closeDrawer }] = useDrawerInner((data) => {
roleId.value = data.record.id;
departId.value = data.record.departId;
loadData();
loadData({
success: (ids) => {
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1619bug
const localData = localStorage.getItem(DEPART_ROLE_AUTH_CONFIG_KEY);
if (localData) {
const obj = JSON.parse(localData);
obj.level && treeMenuClick({ key: obj.level });
obj.expand && treeMenuClick({ key: obj.expand });
} else {
// expandedKeys.value = ids;
}
// update-end--author:liaozhiyang---date:20240704---forTV360X-1619bug
},
});
});
//
const [registerDataRuleDrawer, dataRuleDrawer] = useDrawer();
async function loadData() {
async function loadData(options: any = {}) {
try {
loading.value = true;
//
const { ids, treeList } = await queryTreeListForDeptRole({ departId: departId.value });
if (ids.length > 0) {
allTreeKeys.value = ids;
expandedKeys.value = ids;
// update-begin--author:liaozhiyang---date:20240704---forTV360X-1619bug
options.success?.(ids);
// update-end--author:liaozhiyang---date:20240704---forTV360X-1619bug
//update-begin---author:wangshuai---date:2024-04-08---for:issues/1169 t('') ---
treeData.value = translateTitle(treeList);
//update-end---author:wangshuai---date:2024-04-08---for:issues/1169 t('') ---
@ -107,14 +141,59 @@
loading.value = false;
}
// tree
function onCheck(event) {
/**
* 点击选中
* 2024-07-04
* liaozhiyang
*/
function onCheck(o, e) {
// checkStrictly: true=>false=>.
if (checkStrictly.value) {
checkedKeys.value = event.checked;
checkedKeys.value = o.checked ? o.checked : o;
} else {
checkedKeys.value = event;
const keys = getNodeAllKey(e.node, 'children', 'key');
if (e.checked) {
// keysnew Set
checkedKeys.value = [...new Set([...checkedKeys.value, ...keys])];
} else {
const result = removeMatchingItems(checkedKeys.value, keys);
checkedKeys.value = result;
}
}
}
/**
* 2024-07-04
* liaozhiyang
* 删除相匹配数组的项
*/
function removeMatchingItems(arr1, arr2) {
// 使 arr2
const hashTable = {};
for (const item of arr2) {
hashTable[item] = true;
}
// 使 filter
return arr1.filter((item) => !hashTable[item]);
}
/**
* 2024-07-04
* liaozhiyang
* 获取当前节点及以下所有子孙级的key
*/
function getNodeAllKey(node: any, children: any, key: string) {
const result: any = [];
result.push(node[key]);
const recursion = (data) => {
data.forEach((item: any) => {
result.push(item[key]);
if (item[children]?.length) {
recursion(item[children]);
}
});
};
node[children]?.length && recursion(node[children]);
return result;
}
// tree
function onExpand($expandedKeys) {
@ -158,4 +237,61 @@
}
}
}
/**
* 树菜单选择
* @param key
*/
function treeMenuClick({ key }) {
if (key === 'checkAll') {
checkedKeys.value = allTreeKeys.value;
} else if (key === 'cancelCheck') {
checkedKeys.value = [];
} else if (key === 'openAll') {
expandedKeys.value = allTreeKeys.value;
saveLocalOperation('expand', 'openAll');
} else if (key === 'closeAll') {
expandedKeys.value = [];
saveLocalOperation('expand', 'closeAll');
} else if (key === 'relation') {
checkStrictly.value = false;
saveLocalOperation('level', 'relation');
} else {
checkStrictly.value = true;
saveLocalOperation('level', 'standAlone');
}
}
/**
* 2024-07-04
* liaozhiyang
* */
const saveLocalOperation = (key, value) => {
const localData = localStorage.getItem(DEPART_ROLE_AUTH_CONFIG_KEY);
const obj = localData ? JSON.parse(localData) : {};
obj[key] = value;
localStorage.setItem(DEPART_ROLE_AUTH_CONFIG_KEY, JSON.stringify(obj));
};
</script>
<style lang="less" scoped>
/** 固定操作按钮 */
.jeecg-basic-tree {
position: absolute;
width: 618px;
}
.line {
height: 1px;
width: 100%;
border-bottom: 1px solid #f0f0f0;
}
.more-icon {
font-size: 20px !important;
color: black;
display: inline-flex;
float: right;
margin-right: 2px;
cursor: pointer;
}
:deep(.jeecg-tree-header) {
border-bottom: none;
}
</style>

View File

@ -3,7 +3,7 @@
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="addDepartRole">添加部门角色</a-button>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="addDepartRole" :disabled="!departId">添加部门角色</a-button>
<template v-if="selectedRowKeys.length > 0">
<a-divider type="vertical" />
<a-dropdown>

View File

@ -3,8 +3,8 @@
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="selectAddUser">添加已有用户</a-button>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="createUser">新建用户</a-button>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="selectAddUser" :disabled="!departId">添加已有用户</a-button>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="createUser" :disabled="!departId">新建用户</a-button>
<template v-if="selectedRowKeys.length > 0">
<a-dropdown>
<template #overlay>
@ -29,7 +29,7 @@
</BasicTable>
<UserDrawer @register="registerDrawer" @success="onUserDrawerSuccess" />
<DepartRoleUserAuthDrawer @register="registerUserAuthDrawer" />
<UserSelectModal rowKey="id" @register="registerSelUserModal" @getSelectResult="onSelectUserOk" />
<UserSelectModal ref="userSelectModalRef" rowKey="id" @register="registerSelUserModal" @getSelectResult="onSelectUserOk" />
</template>
<script lang="ts" setup>
@ -50,6 +50,7 @@
const props = defineProps({
data: { require: true, type: Object },
});
const userSelectModalRef: any = ref(null);
// ID
const departId = computed(() => props.data?.id);
@ -93,6 +94,9 @@
beforeFetch(params) {
params.depId = departId.value;
},
// update-begin--author:liaozhiyang---date:20240717---forTV360X-1861
immediate: !!departId.value,
// update-end--author:liaozhiyang---date:20240717---forTV360X-1861
},
});
@ -155,6 +159,9 @@
//
function selectAddUser() {
// update-begin--author:liaozhiyang---date:20240308---forTV360X-1613
userSelectModalRef.value.rowSelection.selectedRowKeys = [];
// update-end--author:liaozhiyang---date:20240308---forTV360X-1613
selUserModal.openModal();
}

View File

@ -1,6 +1,27 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="字典回收站" :showOkBtn="false" width="1000px" destroyOnClose>
<BasicTable @register="registerTable">
<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)" />
@ -13,13 +34,16 @@
import { BasicModal, useModalInner } from '/src/components/Modal';
import { BasicTable, useTable, TableAction } from '/src/components/Table';
import { recycleBincolumns } from '../dict.data';
import { getRecycleBinList, putRecycleBin, deleteRecycleBin } from '../dict.api';
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();
const [registerModal, { setModalProps, closeModal }] = useModalInner(() => {
checkedKeys.value = [];
});
//table
const [registerTable, { reload }] = useTable({
rowKey: 'id',
api: getRecycleBinList,
columns: recycleBincolumns,
striped: true,
@ -39,7 +63,23 @@
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
/**
* 还原事件
*/
@ -57,13 +97,24 @@
* 批量还原事件
*/
function batchHandleRevert() {
handleRevert({ id: toRaw(checkedKeys.value).join(',') });
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() {
handleDelete({ id: toRaw(checkedKeys.value).join(',') });
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) {

View File

@ -11,6 +11,8 @@ enum Api {
exportXls = '/sys/dict/exportXls',
recycleBinList = '/sys/dict/deleteList',
putRecycleBin = '/sys/dict/back',
batchPutRecycleBin = '/sys/dict/putRecycleBin',
batchDeleteRecycleBin = '/sys/dict/deleteRecycleBin',
deleteRecycleBin = '/sys/dict/deletePhysic',
itemList = '/sys/dictItem/list',
deleteItem = '/sys/dictItem/delete',
@ -78,6 +80,16 @@ export const duplicateCheck = (params) => defHttp.get({ url: Api.duplicateCheck,
* @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
@ -87,6 +99,15 @@ export const putRecycleBin = (id, handleSuccess) => {
handleSuccess();
});
};
/**
* 回收站批量删除
* @param params
*/
export const batchDeleteRecycleBin = (params, handleSuccess) => {
return defHttp.delete({ url: `${Api.batchDeleteRecycleBin}?ids=${params.ids}`}).then(() => {
handleSuccess();
});
};
/**
* 回收站删除
* @param params

View File

@ -44,13 +44,13 @@ export const searchFormSchema: FormSchema[] = [
{
label: '字典名称',
field: 'dictName',
component: 'Input',
component: 'JInput',
colProps: { span: 6 },
},
{
label: '字典编码',
field: 'dictCode',
component: 'Input',
component: 'JInput',
colProps: { span: 6 },
},
];

View File

@ -89,7 +89,7 @@
});
//table
const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRowKeys }] = tableContext;
const [registerTable, { reload, updateTableDataRecord }, { rowSelection, selectedRowKeys, selectedRows }] = tableContext;
/**
* 新增事件
@ -127,7 +127,13 @@
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDeleteDict({ ids: selectedRowKeys.value }, reload);
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
});
}
/**
* 成功回调

View File

@ -1,5 +1,5 @@
<template>
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="数据权限规则" :width="adaptiveWidth">
<BasicDrawer v-bind="$attrs" @register="registerDrawer" title="数据权限规则" :width="adaptiveWidth" :rootClassName="prefixCls">
<BasicTable @register="registerTable">
<template #tableTitle>
<a-button type="primary" @click="handleCreate"> 新增</a-button>
@ -21,8 +21,10 @@
import { dataRuleList, deleteRule } from './menu.api';
import { ColEx } from '/@/components/Form/src/types';
import { useDrawerAdaptiveWidth } from '/@/hooks/jeecg/useAdaptiveWidth';
import { useDesign } from '/@/hooks/web/useDesign';
const permissionId = ref('');
const { adaptiveWidth } = useDrawerAdaptiveWidth();
const { prefixCls } = useDesign('sys-menu-dataRulelist');
//model
const [registerModal, { openModal }] = useModal();
const [registerDrawer] = useDrawerInner(async (data) => {
@ -120,3 +122,23 @@
];
}
</script>
<style lang="less">
// -update-begin--author:liaozhiyang---date:20240702---forTV360X-1660-
@prefix-cls: ~'@{namespace}-sys-menu-dataRulelist';
.@{prefix-cls} {
.jeecg-basic-table {
padding: 0;
}
.btnArea {
.ant-btn {
&:last-child {
margin-right: 0;
}
&:first-child {
margin-left: 8px;
}
}
}
}
// -update-end--author:liaozhiyang---date:20240702---forTV360X-1660-
</style>

View File

@ -78,8 +78,8 @@
tableSetting: { fullScreen: true },
formConfig: {
// update-begin--author:liaozhiyang---date:20230803---forQQYUN-5873lablel
labelWidth:60,
owProps: { gutter: 24 },
labelWidth: 74,
rowProps: { gutter: 24 },
// update-end--author:liaozhiyang---date:20230803---forQQYUN-5873lablel
schemas: searchFormSchema,
autoAdvancedCol: 4,
@ -167,7 +167,12 @@
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDeleteMenu({ ids: checkedKeys.value }, reload);
await batchDeleteMenu({ ids: checkedKeys.value }, () => {
// -update-begin--author:liaozhiyang---date:20240702---forTV360X-1662
reload();
checkedKeys.value = [];
// -update-end--author:liaozhiyang---date:20240702---forTV360X-1662
});
}
/**
* 成功回调

View File

@ -399,12 +399,50 @@ export const dataRuleFormSchema: FormSchema[] = [
getPopupContainer: (node) => document.body,
},
},
// update-begin--author:liaozhiyang---date:20240724---forTV360X-1864
{
field: 'ruleValue',
component: 'JInputSelect',
label: '规则值',
component: 'Input',
required: true,
componentProps: {
selectPlaceholder: '可选择系统变量',
inputPlaceholder: '请输入',
getPopupContainer: () => document.body,
selectWidth: '200px',
options: [
{
label: '登录用户账号',
value: '#{sys_user_code}',
},
{
label: '登录用户名称',
value: '#{sys_user_name}',
},
{
label: '当前日期',
value: '#{sys_date}',
},
{
label: '当前时间',
value: '#{sys_time}',
},
{
label: '登录用户部门',
value: '#{sys_org_code}',
},
{
label: '用户拥有部门',
value: '#{sys_multi_org_code}',
},
{
label: '登录用户租户',
value: '#{tenant_id}',
},
],
},
},
// update-end--author:liaozhiyang---date:20240724---forTV360X-1864
{
field: 'status',
label: '状态',

View File

@ -20,5 +20,8 @@
width: 100%;
height: 100%;
min-height: 500px;
// -update-begin--author:liaozhiyang---date:20240702---forTV360X-1685
display: block;
// -update-end--author:liaozhiyang---date:20240702---forTV360X-1685
}
</style>

View File

@ -41,13 +41,16 @@
let values = await validate();
setModalProps({ confirmLoading: true });
//
//update-begin-author:liusq---date:20230404--for: [issue#429]undefined ---
//update-begin-author:liusq---date:20230404--for: [issue#429]undefined ---
if(values.msgType==='ALL'){
values.userIds = '';
}else{
values.userIds += ',';
}
//update-end-author:liusq---date:20230404--for: [issue#429]undefined ---
//update-end-author:liusq---date:20230404--for: [issue#429]undefined ---
if (isUpdate.value) {
values.sendStatus = '0';
}
await saveOrUpdate(values, isUpdate.value);
//
closeModal();

View File

@ -129,7 +129,7 @@
{
label: '编辑',
onClick: handleEdit.bind(null, record),
ifShow: record.sendStatus == 0,
ifShow: record.sendStatus == 0 || record.sendStatus == '2',
},
];
}

View File

@ -95,6 +95,22 @@ export const formSchema: FormSchema[] = [
componentProps: {
placeholder: '请输入标题',
},
// update-begin--author:liaozhiyang---date:20240701---forTV360X-1632
dynamicRules() {
return [
{
validator: (_, value) => {
return new Promise<void>((resolve, reject) => {
if (value.length > 100) {
reject('最长100个字符');
}
resolve();
});
},
},
];
},
// update-end--author:liaozhiyang---date:20240701---forTV360X-1632
},
{
field: 'msgAbstract',
@ -132,7 +148,9 @@ export const formSchema: FormSchema[] = [
required: true,
componentProps: {
rowKey: 'id',
labelKey: 'username',
// update-begin--author:liaozhiyang---date:20240701---forTV360X-1627
labelKey: 'realname',
// update-end--author:liaozhiyang---date:20240701---forTV360X-1627
},
ifShow: ({ values }) => values.msgType == 'USER',
},

View File

@ -144,7 +144,12 @@
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDeleteUserRole({ userIds: checkedKeys.value.join(','), roleId: roleId.value }, reload);
await batchDeleteUserRole({ userIds: checkedKeys.value.join(','), roleId: roleId.value }, () => {
// update-begin--author:liaozhiyang---date:20240701---forTV360X-1655
reload();
checkedKeys.value = [];
// update-end--author:liaozhiyang---date:20240701---forTV360X-1655
});
}
/**

View File

@ -1,5 +1,5 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="用户选择列表" width="1000px" @ok="handleSubmit" destroyOnClose>
<BasicModal v-bind="$attrs" @register="registerModal" title="用户选择列表" width="1000px" @ok="handleSubmit" destroyOnClose @openChange="handleOpenChange">
<BasicTable @register="registerTable" :rowSelection="rowSelection" />
</BasicModal>
</template>
@ -47,6 +47,14 @@
checkedKeys.value = selectedRowKeys;
}
const handleOpenChange = (visible) => {
// -update-begin--author:liaozhiyang---date:20240702---forTV360X-1679-
if (visible) {
checkedKeys.value = [];
}
// -update-end--author:liaozhiyang---date:20240702---forTV360X-1679-
};
//
function handleSubmit() {
setModalProps({ confirmLoading: true });

Some files were not shown because too many files have changed in this diff Show More