@@ -8,6 +8,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -15,19 +26,21 @@
diff --git a/src/components/jeecg/JPrompt/hooks/useJPrompt.ts b/src/components/jeecg/JPrompt/hooks/useJPrompt.ts
new file mode 100644
index 0000000..19ed897
--- /dev/null
+++ b/src/components/jeecg/JPrompt/hooks/useJPrompt.ts
@@ -0,0 +1,56 @@
+import type { JPromptProps } from '../typing';
+import { render, createVNode, nextTick } from 'vue';
+import { error } from '/@/utils/log';
+import JPrompt from '../JPrompt.vue';
+
+export function useJPrompt() {
+ function createJPrompt(options: JPromptProps) {
+ let instance = null;
+ const box = document.createElement('div');
+ const vm = createVNode(JPrompt, {
+ // 注册
+ async onRegister(ins) {
+ instance = ins;
+ await nextTick();
+ ins.openModal(options);
+ },
+ // 销毁
+ afterClose() {
+ render(null, box);
+ document.body.removeChild(box);
+ },
+ });
+ // 挂载到 body
+ render(vm, box);
+ document.body.appendChild(box);
+
+ function getInstance(): any {
+ if (instance == null) {
+ error('useJPrompt instance is undefined!');
+ }
+ return instance;
+ }
+
+ function updateModal(options: JPromptProps) {
+ getInstance()?.updateModal(options);
+ }
+
+ function closeModal() {
+ getInstance()?.closeModal();
+ }
+
+ function setLoading(loading) {
+ getInstance()?.setLoading(loading);
+ }
+
+ return {
+ closeModal,
+ updateModal,
+ setLoading,
+ };
+ }
+
+ return {
+ createJPrompt,
+ };
+}
diff --git a/src/components/jeecg/JPrompt/index.ts b/src/components/jeecg/JPrompt/index.ts
new file mode 100644
index 0000000..850fc09
--- /dev/null
+++ b/src/components/jeecg/JPrompt/index.ts
@@ -0,0 +1,2 @@
+export { useJPrompt } from './hooks/useJPrompt';
+export { default as JPrompt } from './JPrompt.vue';
diff --git a/src/components/jeecg/JPrompt/typing.ts b/src/components/jeecg/JPrompt/typing.ts
new file mode 100644
index 0000000..785efe0
--- /dev/null
+++ b/src/components/jeecg/JPrompt/typing.ts
@@ -0,0 +1,15 @@
+import { ModalOptionsPartial } from '/@/hooks/web/useMessage';
+import { RenderCallbackParams, Rule } from '/@/components/Form';
+
+export interface JPromptProps extends ModalOptionsPartial {
+ // 输入框是否必填
+ required?: boolean;
+ // 校验
+ rules?: Rule[];
+ // 动态校验
+ dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[];
+ // 占位字符
+ placeholder?: string;
+ // 输入框默认值
+ defaultValue?: string;
+}
diff --git a/src/components/jeecg/JVxeTable/src/JVxeTable.ts b/src/components/jeecg/JVxeTable/src/JVxeTable.ts
index 8894206..e88b659 100644
--- a/src/components/jeecg/JVxeTable/src/JVxeTable.ts
+++ b/src/components/jeecg/JVxeTable/src/JVxeTable.ts
@@ -1,4 +1,4 @@
-import { useSlots, defineComponent, getCurrentInstance, h } from 'vue';
+import { defineComponent, h, ref, useSlots } from 'vue';
import { vxeEmits, vxeProps } from './vxe.data';
import { useData, useRefs, useResolveComponent as rc } from './hooks/useData';
import { useColumns } from './hooks/useColumns';
@@ -16,11 +16,11 @@ export default defineComponent({
props: vxeProps(),
emits: [...vxeEmits],
setup(props: JVxeTableProps, context) {
- const instance = getCurrentInstance();
+ const instanceRef = ref();
const refs = useRefs();
const slots = useSlots();
const data = useData(props);
- const { methods, publicMethods, created } = useMethods(props, context, data, refs, instance);
+ const { methods, publicMethods, created } = useMethods(props, context, data, refs, instanceRef);
created();
useColumns(props, data, methods, slots);
useDataSource(props, data, methods, refs);
@@ -30,6 +30,7 @@ export default defineComponent({
// 渲染子组件
const renderComponents = useRenderComponents(props, data, methods, slots);
return {
+ instanceRef,
...refs,
...publicMethods,
...finallyProps,
@@ -69,4 +70,7 @@ export default defineComponent({
)
);
},
+ created() {
+ this.instanceRef = this;
+ },
});
diff --git a/src/components/jeecg/JVxeTable/src/hooks/useData.ts b/src/components/jeecg/JVxeTable/src/hooks/useData.ts
index a9e666f..29a7570 100644
--- a/src/components/jeecg/JVxeTable/src/hooks/useData.ts
+++ b/src/components/jeecg/JVxeTable/src/hooks/useData.ts
@@ -32,13 +32,13 @@ export function useData(props: JVxeTableProps): JVxeDataProps {
iconClose: 'ant-table-row-expand-icon ant-table-row-collapsed',
iconOpen: 'ant-table-row-expand-icon ant-table-row-expanded',
},
- // 虚拟滚动配置,y轴大于30条数据时启用虚拟滚动
- // 'scroll-y': {
- // gt: 30
- // },
- // 'scroll-x': {
- // gt: 15
- // },
+ // 虚拟滚动配置,y轴大于xx条数据时启用虚拟滚动
+ scrollY: {
+ gt: 30,
+ },
+ scrollX: {
+ gt: 20,
+ },
radioConfig: { highlight: true },
checkboxConfig: { highlight: true },
mouseConfig: { selected: false },
diff --git a/src/components/jeecg/JVxeTable/src/hooks/useJVxeComponent.ts b/src/components/jeecg/JVxeTable/src/hooks/useJVxeComponent.ts
index e5ecb49..a52b68b 100644
--- a/src/components/jeecg/JVxeTable/src/hooks/useJVxeComponent.ts
+++ b/src/components/jeecg/JVxeTable/src/hooks/useJVxeComponent.ts
@@ -138,13 +138,14 @@ export function useJVxeComponent(props: JVxeComponent.Props) {
/** 通用处理 change 事件 */
function handleChangeCommon($value) {
- let getValue = enhanced.getValue($value, ctx);
- trigger('change', { value: getValue });
+ let newValue = enhanced.getValue($value, ctx);
+ let oldValue = value.value;
+ trigger('change', { value: newValue });
// 触发valueChange事件
parentTrigger('valueChange', {
type: props.type,
- value: getValue,
- oldValue: value.value,
+ value: newValue,
+ oldValue: oldValue,
col: originColumn.value,
rowIndex: rowIndex.value,
columnIndex: columnIndex.value,
diff --git a/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts b/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts
index b16f116..d678427 100644
--- a/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts
+++ b/src/components/jeecg/JVxeTable/src/hooks/useMethods.ts
@@ -1,4 +1,4 @@
-import { watch } from 'vue';
+import { Ref, watch } from 'vue';
import XEUtils from 'xe-utils';
import { simpleDebounce } from '/@/utils/common/compUtils';
import { JVxeDataProps, JVxeRefs, JVxeTableProps, JVxeTypes } from '../types';
@@ -10,7 +10,7 @@ import { useLinkage } from './useLinkage';
import { useWebSocket } from './useWebSocket';
import { getPrefix, getJVxeAuths } from '../utils/authUtils';
-export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps, refs: JVxeRefs, instance) {
+export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps, refs: JVxeRefs, instanceRef: Ref) {
let xTableTemp: VxeTableInstance & VxeTablePrivateMethods;
function getXTable() {
@@ -37,6 +37,7 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
getNewRowById,
getDeleteData,
getSelectionData,
+ getSelectedData,
removeRows,
removeRowsById,
removeSelection,
@@ -159,13 +160,13 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
// 单元格被激活编辑时会触发该事件
function handleEditActived({ column }) {
// 执行增强
- getEnhanced(column.params.type).aopEvents.editActived!.apply(instance, arguments as any);
+ getEnhanced(column.params.type).aopEvents.editActived!.apply(instanceRef.value, arguments as any);
}
// 单元格编辑状态下被关闭时会触发该事件
function handleEditClosed({ column }) {
// 执行增强
- getEnhanced(column.params.type).aopEvents.editClosed!.apply(instance, arguments as any);
+ getEnhanced(column.params.type).aopEvents.editClosed!.apply(instanceRef.value, arguments as any);
}
// 返回值决定行是否可选中
@@ -189,7 +190,7 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
return false;
}
// 执行增强
- return getEnhanced(column.params.type).aopEvents.activeMethod!.apply(instance, arguments as any) ?? true;
+ return getEnhanced(column.params.type).aopEvents.activeMethod!.apply(instanceRef.value, arguments as any) ?? true;
})();
if (!flag) {
getXTable().clearActived();
@@ -351,7 +352,7 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
rows: result.rows,
insertIndex: index,
$table: xTable,
- target: instance,
+ target: instanceRef.value,
});
}
}
@@ -579,7 +580,7 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
/** 清空选择行 */
async function clearSelection() {
const xTable = getXTable();
- let event = { $table: xTable, target: instance };
+ let event = { $table: xTable, target: instanceRef.value };
if (props.rowSelectionType === JVxeTypes.rowRadio) {
await xTable.clearRadioRow();
handleVxeRadioChange(event);
@@ -745,13 +746,38 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
// 触发事件
function trigger(name, event: any = {}) {
- event.$target = instance;
+ event.$target = instanceRef.value;
event.$table = getXTable();
//online增强参数兼容
- event.target = instance;
+ event.target = instanceRef.value;
emit(name, event);
}
+ /**
+ * 获取选中的行-和 getSelectionData 区别在于对于新增的行也会返回ID
+ * 用于onlinePopForm
+ * @param isFull
+ */
+ function getSelectedData(isFull?: boolean) {
+ const xTable = getXTable();
+ let rows: any[] = [];
+ if (props.rowSelectionType === JVxeTypes.rowRadio) {
+ let row = xTable.getRadioRecord(isFull);
+ if (isNull(row)) {
+ return [];
+ }
+ rows = [row];
+ } else {
+ rows = xTable.getCheckboxRecords(isFull);
+ }
+ let records: Recordable[] = [];
+ for (let row of rows) {
+ let item = cloneDeep(row);
+ records.push(item);
+ }
+ return records;
+ }
+
return {
methods: {
trigger,
diff --git a/src/components/jeecg/JVxeTable/src/hooks/useToolbar.ts b/src/components/jeecg/JVxeTable/src/hooks/useToolbar.ts
index 2a716ca..15ab824 100644
--- a/src/components/jeecg/JVxeTable/src/hooks/useToolbar.ts
+++ b/src/components/jeecg/JVxeTable/src/hooks/useToolbar.ts
@@ -24,7 +24,7 @@ export function useToolbar(props: JVxeTableProps, data: JVxeDataProps, methods:
let deleteRows = methods.filterNewRows(data.selectedRows.value);
// 触发删除事件
if (deleteRows.length > 0) {
- let removeEvent: any = { deleteRows, $table, target: this };
+ let removeEvent: any = { deleteRows, $table };
if (props.asyncRemove) {
// 确认删除,只有调用这个方法才会真删除
removeEvent.confirmRemove = () => methods.removeSelection();
diff --git a/src/components/jeecg/JVxeTable/src/hooks/useWebSocket.ts b/src/components/jeecg/JVxeTable/src/hooks/useWebSocket.ts
index 9605a90..ba0d355 100644
--- a/src/components/jeecg/JVxeTable/src/hooks/useWebSocket.ts
+++ b/src/components/jeecg/JVxeTable/src/hooks/useWebSocket.ts
@@ -58,7 +58,7 @@ const vs = {
const url = `${domain}/vxeSocket/${userId}/${this.pageId}`;
//update-begin-author:taoyan date:2022-4-24 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
let token = (getToken() || '') as string;
- this.ws = new WebSocket(url);
+ this.ws = new WebSocket(url, [token]);
//update-end-author:taoyan date:2022-4-24 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
this.ws.onopen = this.on.open.bind(this);
this.ws.onerror = this.on.error.bind(this);
diff --git a/src/components/jeecg/OnLine/hooks/usePopBiz.ts b/src/components/jeecg/OnLine/hooks/usePopBiz.ts
index 718ce1e..a99d3a6 100644
--- a/src/components/jeecg/OnLine/hooks/usePopBiz.ts
+++ b/src/components/jeecg/OnLine/hooks/usePopBiz.ts
@@ -40,7 +40,7 @@ export function usePopBiz(props, tableRef?) {
getColumns: '/online/cgreport/api/getRpColumns/',
getData: '/online/cgreport/api/getData/',
getQueryInfo: '/online/cgreport/api/getQueryInfo/',
- export: '/online/cgreport/api/exportXls/',
+ export: '/online/cgreport/api/exportManySheetXls/',
});
//已选择的值
const checkedKeys = ref
>([]);
@@ -289,11 +289,12 @@ export function usePopBiz(props, tableRef?) {
for (let column of columns) {
if (column.isTotal === '1') {
arr.push(column.dataIndex!);
- if (column.children && column.children.length > 0) {
- let subArray = getNeedSumColumns(column.children);
- if (subArray.length > 0) {
- arr.push(...subArray);
- }
+ }
+ // 【VUEN-1569】【online报表】合计无效
+ if (column.children && column.children.length > 0) {
+ let subArray = getNeedSumColumns(column.children);
+ if (subArray.length > 0) {
+ arr.push(...subArray);
}
}
}
@@ -445,6 +446,14 @@ export function usePopBiz(props, tableRef?) {
const { handleExportXls } = useMethods();
let url = `${configUrl.export}${cgRpConfigId.value}`;
let params = getQueryParams(); //查询条件
+ // 【VUEN-1568】如果选中了某些行,就只导出选中的行
+ let keys = unref(checkedKeys);
+ if (keys.length > 0) {
+ params['force_id'] = keys
+ .map((i) => (getRowByKey(i) as any)?.id)
+ .filter((i) => i != null && i !== '')
+ .join(',');
+ }
handleExportXls(title.value, url, params);
}
diff --git a/src/components/jeecg/super/superquery/SuperQuery.vue b/src/components/jeecg/super/superquery/SuperQuery.vue
new file mode 100644
index 0000000..4203f3a
--- /dev/null
+++ b/src/components/jeecg/super/superquery/SuperQuery.vue
@@ -0,0 +1,401 @@
+
+
+
+
+
+
+
+
+
+
+ 确定
+ 关闭
+
+
+
+
+
+
+
+
+
+
+
+
+ AND(所有条件都要求匹配)
+ OR(条件中的任意一个匹配)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 等于
+ 模糊
+ 以..开始
+ 以..结尾
+ 在...中
+ 不等于
+ 大于
+ 大于等于
+ 小于
+ 小于等于
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存的查询
+
+
+
+
+ {{ title.length > 10 ? title.substring(0, 10) + '...' : title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/jeecg/super/superquery/SuperQueryValComponent.vue b/src/components/jeecg/super/superquery/SuperQueryValComponent.vue
new file mode 100644
index 0000000..61ee043
--- /dev/null
+++ b/src/components/jeecg/super/superquery/SuperQueryValComponent.vue
@@ -0,0 +1,98 @@
+
diff --git a/src/components/jeecg/super/superquery/useSuperQuery.ts b/src/components/jeecg/super/superquery/useSuperQuery.ts
new file mode 100644
index 0000000..bc5181a
--- /dev/null
+++ b/src/components/jeecg/super/superquery/useSuperQuery.ts
@@ -0,0 +1,524 @@
+import { useModalInner } from '/@/components/Modal';
+import { randomString } from '/@/utils/common/compUtils';
+import { reactive, ref, toRaw, watch } from 'vue';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { Modal } from 'ant-design-vue';
+import { createLocalStorage } from '/@/utils/cache';
+import { useRoute } from 'vue-router';
+import FormSchemaFactory from '/@/views/super/online/cgform/auto/comp/factory/FormSchemaFactory';
+/**
+ * 表单类型转换成查询类型
+ * 普通查询和高级查询组件区别 :高级查询不支持联动组件
+ */
+const FORM_VIEW_TO_QUERY_VIEW = {
+ password: 'text',
+ file: 'text',
+ image: 'text',
+ textarea: 'text',
+ umeditor: 'text',
+ markdown: 'text',
+ checkbox: 'list_multi',
+ radio: 'list',
+};
+
+// 查询条件存储编码前缀
+const SAVE_CODE_PRE = 'JSuperQuerySaved_';
+
+/**
+ * 查询项
+ * */
+interface SuperQueryItem {
+ field: string | undefined;
+ rule: string | undefined;
+ val: string | number;
+ key: string;
+}
+/**
+ * 查询项-第一个控件树model
+ * */
+interface TreeModel {
+ title: string;
+ value: string;
+ isLeaf?: boolean;
+ disabled?: boolean;
+ children?: TreeModel[];
+ order?: number;
+}
+
+/**
+ * 查询信息保存结构
+ * */
+interface SaveModel {
+ title: string;
+ content: string;
+ type: string;
+}
+
+export function useSuperQuery() {
+ const { createMessage: $message } = useMessage();
+ /** 表单ref*/
+ const formRef = ref();
+
+ /** 数据*/
+ const dynamicRowValues = reactive<{ values: SuperQueryItem[] }>({
+ values: [],
+ });
+ /** and/or */
+ const matchType = ref('and');
+
+ // 弹框显示
+ const [registerModal, { setModalProps }] = useModalInner(() => {
+ setModalProps({ confirmLoading: false });
+ });
+
+ // 高级查询类型不支持联动组件,需要额外设置联动组件的view为text
+ const view2QueryViewMap = Object.assign({}, { link_down: 'text' }, FORM_VIEW_TO_QUERY_VIEW);
+
+ /**
+ * 确认按钮事件
+ */
+ function handleSubmit() {
+ console.log('handleSubmit', dynamicRowValues.values);
+ }
+
+ /**
+ * 关闭按钮事件
+ */
+ function handleCancel() {
+ //closeModal();
+ }
+
+ /**
+ * val组件赋值
+ */
+ function setFormModel(key: string, value: any, item: any) {
+ console.log('setFormModel', key, value);
+ // formModel[key] = value;
+ item['val'] = value;
+ }
+
+ // 字段-Properties
+ const fieldProperties = ref({});
+ // 字段-左侧查询项-树控件数据
+ const fieldTreeData = ref([]);
+
+ /**
+ * 初始化数据-最开始的方法
+ * 1.获取 表名@字段名-->配置 这样的一个map
+ * 2.获取树形结构的数据 显示:文本; 存储:表名@字段名
+ * 当树改变时,及时获取配置更新表单
+ * @param json
+ */
+ function init(json) {
+ let { allFields, treeData } = getAllFields(json);
+ fieldProperties.value = allFields;
+ fieldTreeData.value = treeData;
+ }
+
+ /**
+ * 左侧查询项 添加一行
+ * @param index
+ */
+ function addOne(index) {
+ let item = {
+ field: undefined,
+ rule: 'eq',
+ val: '',
+ key: randomString(16),
+ };
+ if (index === false) {
+ // 重置后需要调用
+ dynamicRowValues.values = [];
+ dynamicRowValues.values.push(item);
+ } else if (index === true) {
+ // 打开弹框是需要调用
+ if (dynamicRowValues.values.length == 0) {
+ dynamicRowValues.values.push(item);
+ }
+ } else {
+ // 其余就是 正常的点击加号增加行
+ dynamicRowValues.values.splice(++index, 0, item);
+ }
+ }
+
+ /**
+ * 左侧查询项 删除一行
+ */
+ function removeOne(item: SuperQueryItem) {
+ let arr = toRaw(dynamicRowValues.values);
+ let index = -1;
+ for (let i = 0; i < arr.length; i++) {
+ if (item.key == arr[i].key) {
+ index = i;
+ break;
+ }
+ }
+ if (index != -1) {
+ dynamicRowValues.values.splice(index, 1);
+ }
+ }
+
+ // 默认的输入框
+ const defaultInput = {
+ field: 'val',
+ label: '测试',
+ component: 'Input',
+ };
+
+ /**
+ * 左侧查询项 val组件 schema获取, 替代左侧字段树的change事件
+ * @param item
+ * @param index
+ */
+ function getSchema(item, index) {
+ let map = fieldProperties.value;
+ let prop = map[item.field];
+ if (!prop) {
+ return defaultInput;
+ }
+ if (view2QueryViewMap[prop.view]) {
+ // 如果出现查询条件联动组件出来的场景,请跟踪此处
+ prop.view = view2QueryViewMap[prop.view];
+ }
+ let temp = FormSchemaFactory.createFormSchema(item.field, prop);
+ // temp.setFormRef(formRef)
+ temp.noChange();
+ // 查询条件中的 下拉框popContainer为parentNode
+ temp.asSearchForm();
+ temp.updateField(item.field + index);
+ const setFieldValue = (values) => {
+ item['val'] = values[item.field];
+ };
+ temp.setFunctionForFieldValue(setFieldValue);
+ let schema = temp.getFormItemSchema();
+ //schema['valueField'] = 'val'
+ return schema;
+ }
+
+ /*-----------------------右侧保存信息相关-begin---------------------------*/
+
+ /**
+ * 右侧树 的 数据
+ */
+ const saveTreeData = ref('');
+ // 本地缓存
+ const $ls = createLocalStorage();
+ //需要保存的信息(一条)
+ const saveInfo = reactive({
+ visible: false,
+ title: '',
+ content: '',
+ saveCode: '',
+ });
+ //按钮loading
+ const loading = ref(false);
+
+ // 当前页面路由
+ const route = useRoute();
+ // 监听路由信息,路由发生改变,则重新获取保存的查询信息-->currentPageSavedArray
+ watch(
+ () => route.fullPath,
+ (val) => {
+ console.log('fullpath', val);
+ initSaveQueryInfoCode();
+ }
+ );
+
+ // 当前页面存储的 查询信息
+ const currentPageSavedArray = ref([]);
+ // 监听当前页面是否有新的数据保存了,然后更新右侧数据->saveTreeData
+ watch(
+ () => currentPageSavedArray.value,
+ (val) => {
+ let temp: any[] = [];
+ if (val && val.length > 0) {
+ val.map((item) => {
+ let key = randomString(16);
+ temp.push({
+ title: item.title,
+ slots: { icon: 'custom' },
+ value: key,
+ });
+ });
+ }
+ saveTreeData.value = temp;
+ },
+ { immediate: true, deep: true }
+ );
+
+ // 重新获取保存的查询信息
+ function initSaveQueryInfoCode() {
+ let code = SAVE_CODE_PRE + route.fullPath;
+ saveInfo.saveCode = code;
+ let list = $ls.get(code);
+ if (list && list instanceof Array) {
+ currentPageSavedArray.value = list;
+ }
+ }
+
+ // 执行一次 获取保存的查询信息
+ initSaveQueryInfoCode();
+
+ /**
+ * 保存按钮事件
+ */
+ function handleSave() {
+ // 获取实际数据转成字符串
+ let fieldArray = getQueryInfo();
+ if (!fieldArray) {
+ $message.warning('空条件不能保存');
+ return;
+ }
+ let content = JSON.stringify(fieldArray);
+ openSaveInfoModal(content);
+ }
+
+ // 输入保存标题 弹框显示
+ function openSaveInfoModal(content) {
+ saveInfo.visible = true;
+ saveInfo.title = '';
+ saveInfo.content = content;
+ }
+
+ /**
+ * 确认保存查询信息
+ */
+ function doSaveQueryInfo() {
+ let { title, content, saveCode } = saveInfo;
+ let index = getTitleIndex(title);
+ if (index >= 0) {
+ // 已存在是否覆盖
+ Modal.confirm({
+ title: '提示',
+ content: `${title} 已存在,是否覆盖?`,
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ currentPageSavedArray.value.splice(index, 1, {
+ content,
+ title,
+ type: matchType.value,
+ });
+ $ls.set(saveCode, currentPageSavedArray.value);
+ saveInfo.visible = false;
+ },
+ });
+ } else {
+ currentPageSavedArray.value.push({
+ content,
+ title,
+ type: matchType.value,
+ });
+ $ls.set(saveCode, currentPageSavedArray.value);
+ saveInfo.visible = false;
+ }
+ }
+
+ // 根据填入的 title找本地存储的信息,如果有需要询问是否覆盖
+ function getTitleIndex(title) {
+ let savedArray = currentPageSavedArray.value;
+ let index = -1;
+ for (let i = 0; i < savedArray.length; i++) {
+ if (savedArray[i].title == title) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+
+ /**
+ * 获取左侧所有查询条件,如果没有/或者条件无效则返回false
+ */
+ function getQueryInfo(isEmit = false) {
+ let arr = dynamicRowValues.values;
+ if (!arr || arr.length == 0) {
+ return false;
+ }
+ let fieldArray: any = [];
+ let fieldProps = fieldProperties.value;
+ for (let item of arr) {
+ if (item.field && (item.val || item.val === 0) && item.rule) {
+ let tempVal: any = toRaw(item.val);
+ if (tempVal instanceof Array) {
+ tempVal = tempVal.join(',');
+ }
+ let fieldName = getRealFieldName(item);
+ let obj = {
+ field: fieldName,
+ rule: item.rule,
+ val: tempVal,
+ };
+ if (isEmit === true) {
+ //如果当前数据用于emit事件,需要设置dbtype和type
+ let prop = fieldProps[item.field];
+ if (prop) {
+ obj['type'] = prop.view;
+ obj['dbType'] = prop.type;
+ }
+ }
+ fieldArray.push(obj);
+ }
+ }
+ if (fieldArray.length == 0) {
+ return false;
+ }
+ return fieldArray;
+ }
+
+ //update-begin-author:taoyan date:2022-5-31 for: VUEN-1148 主子联动下,高级查询查子表数据,无效
+ /**
+ * 高级查询参数 字段名
+ * 获取后台需要的 字段名格式:表名,字段名
+ * @param item
+ */
+ function getRealFieldName(item) {
+ let fieldName = item.field;
+ if (fieldName.indexOf('@') > 0) {
+ fieldName = fieldName.replace('@', ',');
+ }
+ return fieldName;
+ }
+ //update-end-author:taoyan date:2022-5-31 for: VUEN-1148 主子联动下,高级查询查子表数据,无效
+
+ /**
+ * 右侧数据 点击事件,重新将数据显示到左侧
+ * @param key
+ * @param node
+ */
+ function handleTreeSelect(key, { node }) {
+ console.log(key, node);
+ let title = node.dataRef.title;
+ let arr = currentPageSavedArray.value.filter((item) => item.title == title);
+ if (arr && arr.length > 0) {
+ // 拿到数据渲染
+ let { content, type } = arr[0];
+ let data = JSON.parse(content);
+ let rowsValues: SuperQueryItem[] = [];
+ for (let item of data) {
+ rowsValues.push(Object.assign({}, { key: randomString(16) }, item));
+ }
+ dynamicRowValues.values = rowsValues;
+ matchType.value = type;
+ }
+ }
+
+ /**
+ * 右侧数据 删除事件
+ */
+ function handleRemoveSaveInfo(title) {
+ console.log(title);
+ let index = getTitleIndex(title);
+ if (index >= 0) {
+ currentPageSavedArray.value.splice(index, 1);
+ $ls.set(saveInfo.saveCode, currentPageSavedArray.value);
+ }
+ }
+
+ /*-----------------------右侧保存信息相关-end---------------------------*/
+
+ // 获取所有字段配置信息
+ function getAllFields(properties) {
+ // 获取所有配置 查询字段 是否联合查询
+ // const {properties, table, title } = json;
+ let allFields = {};
+ let order = 1;
+ let treeData: TreeModel[] = [];
+ /* let mainNode:TreeModel = {
+ title,
+ value: table,
+ disabled: true,
+ children: []
+ };*/
+ //treeData.push(mainNode)
+ Object.keys(properties).map((field) => {
+ let item = properties[field];
+ if (item.view == 'table') {
+ // 子表字段
+ // 联合查询开启才需要子表字段作为查询条件
+ let subProps = item['properties'] || item['fields'];
+ let subTableOrder = order * 100;
+ let subNode: TreeModel = {
+ title: item.title,
+ value: field,
+ disabled: true,
+ children: [],
+ order: subTableOrder,
+ };
+ Object.keys(subProps).map((subField) => {
+ let subItem = subProps[subField];
+ // 保证排序统一
+ subItem['order'] = subTableOrder + subItem['order'];
+ let subFieldKey = field + '@' + subField;
+ allFields[subFieldKey] = subItem;
+ subNode.children!.push({
+ title: subItem.title,
+ value: subFieldKey,
+ isLeaf: true,
+ order: subItem['order'],
+ });
+ });
+ orderField(subNode);
+ treeData.push(subNode);
+ order++;
+ } else {
+ // 主表字段
+ //let fieldKey = table+'@'+field
+ let fieldKey = field;
+ allFields[fieldKey] = item;
+ treeData.push({
+ title: item.title,
+ value: fieldKey,
+ isLeaf: true,
+ order: item.order,
+ });
+ }
+ });
+ orderField(treeData);
+ return { allFields, treeData };
+ }
+
+ //根据字段的order重新排序
+ function orderField(data) {
+ let arr = data.children || data;
+ arr.sort(function (a, b) {
+ return a.order - b.order;
+ });
+ }
+
+ function initDefaultValues(values) {
+ const { params, matchType } = values;
+ if (params) {
+ let rowsValues: SuperQueryItem[] = [];
+ for (let item of params) {
+ rowsValues.push(Object.assign({}, { key: randomString(16) }, item));
+ }
+ dynamicRowValues.values = rowsValues;
+ matchType.value = matchType;
+ }
+ }
+
+ return {
+ formRef,
+ init,
+ dynamicRowValues,
+ matchType,
+ registerModal,
+ handleSubmit,
+ handleCancel,
+ handleSave,
+ doSaveQueryInfo,
+ saveInfo,
+ saveTreeData,
+ handleRemoveSaveInfo,
+ handleTreeSelect,
+ fieldTreeData,
+ addOne,
+ removeOne,
+ setFormModel,
+ getSchema,
+ loading,
+ getQueryInfo,
+ initDefaultValues,
+ };
+}
diff --git a/src/design/index.less b/src/design/index.less
index 013e7b6..c82d94b 100644
--- a/src/design/index.less
+++ b/src/design/index.less
@@ -3,6 +3,7 @@
@import 'public.less';
@import 'ant/index.less';
@import './theme.less';
+@import './lowApp/global.less';
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 1000px white inset !important;
diff --git a/src/design/lowApp/global.less b/src/design/lowApp/global.less
new file mode 100644
index 0000000..fe70bc4
--- /dev/null
+++ b/src/design/lowApp/global.less
@@ -0,0 +1,30 @@
+// ---------------
+// lowApp全局样式
+// ---------------
+
+// 生成display样式
+.low-app-display(@type) {
+ display: @type !important;
+
+ & + .ant-divider,
+ & + .ant-dropdown-menu-item-divider {
+ display: @type !important;
+ }
+}
+
+// lowApp外隐藏
+.low-app-show {
+ .low-app-display(none);
+}
+
+[data-low-app] {
+ // lowApp内隐藏
+ .low-app-hide {
+ .low-app-display(none);
+ }
+
+ // lowApp内显示
+ .low-app-show {
+ .low-app-display(block);
+ }
+}
diff --git a/src/enums/httpEnum.ts b/src/enums/httpEnum.ts
index 2c4df60..422b762 100644
--- a/src/enums/httpEnum.ts
+++ b/src/enums/httpEnum.ts
@@ -45,4 +45,6 @@ export enum ConfigEnum {
TENANT_ID = 'tenant-id',
// 版本
VERSION = 'X-Version',
+ // 低代码应用ID
+ X_LOW_APP_ID = 'X-Low-App-ID',
}
diff --git a/src/enums/jeecgEnum.ts b/src/enums/jeecgEnum.ts
index 9290893..4239ea6 100644
--- a/src/enums/jeecgEnum.ts
+++ b/src/enums/jeecgEnum.ts
@@ -18,4 +18,6 @@ export enum JInputTypeEnum {
export enum JDragConfigEnum {
//baseURL
DRAG_BASE_URL = 'drag-base-url',
+ //拖拽缓存前缀
+ DRAG_CACHE_PREFIX = 'drag-cache:',
}
diff --git a/src/enums/pageEnum.ts b/src/enums/pageEnum.ts
index 13f1068..d97c589 100644
--- a/src/enums/pageEnum.ts
+++ b/src/enums/pageEnum.ts
@@ -7,4 +7,6 @@ export enum PageEnum {
ERROR_PAGE = '/exception',
// error log page path
ERROR_LOG_PAGE = '/error-log/list',
+ // auth2登录路由路径
+ OAUTH2_LOGIN_PAGE_PATH = '/oauth2-app/login',
}
diff --git a/src/hooks/web/useWebSocket.ts b/src/hooks/web/useWebSocket.ts
index b7c4506..5fbdee0 100644
--- a/src/hooks/web/useWebSocket.ts
+++ b/src/hooks/web/useWebSocket.ts
@@ -28,7 +28,7 @@ export function connectWebSocket(url: string) {
autoReconnect: true,
// 心跳检测
heartbeat: false,
- //protocols: [token],
+ protocols: [token],
});
//update-end-author:taoyan date:2022-4-24 for: v2.4.6 的 websocket 服务端,存在性能和安全问题。 #3278
result.value.open();
diff --git a/src/layouts/default/header/components/notify/index.vue b/src/layouts/default/header/components/notify/index.vue
index d2dcbd6..b3f8c24 100644
--- a/src/layouts/default/header/components/notify/index.vue
+++ b/src/layouts/default/header/components/notify/index.vue
@@ -144,7 +144,12 @@
function onWebSocketMessage(data) {
if (data.cmd === 'topic' || data.cmd === 'user') {
- loadData();
+ //update-begin-author:taoyan date:2022-7-13 for: VUEN-1674【严重bug】系统通知,为什么必须刷新右上角才提示
+ //后台保存数据太慢 前端延迟刷新消息
+ setTimeout(() => {
+ loadData();
+ }, 1000);
+ //update-end-author:taoyan date:2022-7-13 for: VUEN-1674【严重bug】系统通知,为什么必须刷新右上角才提示
}
}
diff --git a/src/layouts/default/index.vue b/src/layouts/default/index.vue
index 4a230ba..c8fe28c 100644
--- a/src/layouts/default/index.vue
+++ b/src/layouts/default/index.vue
@@ -14,7 +14,7 @@
+
+
diff --git a/src/views/demo/vextable/form/JeecgOrderMainForm.vue b/src/views/demo/vextable/form/JeecgOrderMainForm.vue
new file mode 100644
index 0000000..4a8fcc1
--- /dev/null
+++ b/src/views/demo/vextable/form/JeecgOrderMainForm.vue
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
diff --git a/src/views/demo/vextable/index.vue b/src/views/demo/vextable/index.vue
index 1f73b59..1fb72e3 100644
--- a/src/views/demo/vextable/index.vue
+++ b/src/views/demo/vextable/index.vue
@@ -56,7 +56,7 @@
};
const getDropDownActions = (record) => {
- return [
+ let arr = [
{
label: '删除',
popConfirm: {
@@ -65,6 +65,7 @@
},
},
];
+ return arr;
};
// 列表页面公共参数、方法
diff --git a/src/views/demo/vextable/jvxetable/jvxetable.data.ts b/src/views/demo/vextable/jvxetable/jvxetable.data.ts
index f746647..a790826 100644
--- a/src/views/demo/vextable/jvxetable/jvxetable.data.ts
+++ b/src/views/demo/vextable/jvxetable/jvxetable.data.ts
@@ -1,4 +1,4 @@
-import { JVxeTypes, JVxeColumn } from '/src/components/jeecg/JVxeTable/types';
+import { JVxeTypes, JVxeColumn } from '/@/components/jeecg/JVxeTable/types';
export const columns: JVxeColumn[] = [
{
diff --git a/src/views/monitor/mynews/DetailModal.vue b/src/views/monitor/mynews/DetailModal.vue
index 1d6357a..38a3611 100644
--- a/src/views/monitor/mynews/DetailModal.vue
+++ b/src/views/monitor/mynews/DetailModal.vue
@@ -4,12 +4,21 @@
+
+
diff --git a/src/views/sys/login/useLogin.ts b/src/views/sys/login/useLogin.ts
index 34456be..6d306e4 100644
--- a/src/views/sys/login/useLogin.ts
+++ b/src/views/sys/login/useLogin.ts
@@ -163,3 +163,22 @@ async function checkPhone(rule, value, callback) {
});
}
}
+
+//update-begin---author:wangshuai ---date:20220629 for:[issues/I5BG1I]vue3不支持auth2登录------------
+/**
+ * 判断是否是OAuth2APP环境
+ */
+export function isOAuth2AppEnv() {
+ return /wxwork|dingtalk/i.test(navigator.userAgent);
+}
+
+/**
+ * 后台构造oauth2登录地址
+ * @param source
+ */
+export function sysOAuth2Login(source) {
+ let url = `${window._CONFIG['domianURL']}/sys/thirdLogin/oauth2/${source}/login`;
+ url += `?state=${encodeURIComponent(window.location.origin)}`;
+ window.location.href = url;
+}
+//update-end---author:wangshuai ---date:20220629 for:[issues/I5BG1I]vue3不支持auth2登录------------
diff --git a/src/views/system/address/index.vue b/src/views/system/address/index.vue
index 6b2f328..0b9cf64 100644
--- a/src/views/system/address/index.vue
+++ b/src/views/system/address/index.vue
@@ -45,7 +45,9 @@
tableProps: {
api: list,
columns,
- rowKey: 'id',
+ //update-begin---author:wangshuai ---date:20220629 for:[VUEN-1485]进入系统管理--通讯录页面后,网页命令行报错------------
+ rowKey: 'userId',
+ //update-end---author:wangshuai ---date:20220629 for:[VUEN-1485]进入系统管理--通讯录页面后,网页命令行报错--------------
showIndexColumn: true,
formConfig: {
labelWidth: 200,
diff --git a/src/views/system/examples/demo/DemoDetailModal.vue b/src/views/system/examples/demo/DemoDetailModal.vue
new file mode 100644
index 0000000..6418a09
--- /dev/null
+++ b/src/views/system/examples/demo/DemoDetailModal.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
+
diff --git a/src/views/system/examples/demo/index.vue b/src/views/system/examples/demo/index.vue
index 68e8dc8..399fdcb 100644
--- a/src/views/system/examples/demo/index.vue
+++ b/src/views/system/examples/demo/index.vue
@@ -52,12 +52,14 @@
导入
- 导出
+ 导出
高级查询?
打开Tab页
{{ customSearch ? '表单配置查询' : '自定义查询' }}
弹窗导入
+
+
@@ -78,11 +80,12 @@
+
diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue
index 97558ff..e0c1569 100644
--- a/src/views/system/role/index.vue
+++ b/src/views/system/role/index.vue
@@ -30,8 +30,8 @@
diff --git a/src/views/system/role/role.data.ts b/src/views/system/role/role.data.ts
index df9b268..2d2393b 100644
--- a/src/views/system/role/role.data.ts
+++ b/src/views/system/role/role.data.ts
@@ -143,6 +143,21 @@ export const roleIndexFormSchema: FormSchema[] = [
component: 'Input',
required: true,
},
+ {
+ label: '组件地址',
+ field: 'component',
+ component: 'Input',
+ componentProps: {
+ placeholder: '请输入前端组件',
+ },
+ required: true,
+ },
+ {
+ field: 'route',
+ label: '是否路由菜单',
+ component: 'Switch',
+ defaultValue: true,
+ },
{
label: '优先级',
field: 'priority',
diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue
index 08180c6..7a6d618 100644
--- a/src/views/system/user/index.vue
+++ b/src/views/system/user/index.vue
@@ -4,7 +4,7 @@