diff --git a/extend/base/admin/view/common/_require.html b/extend/base/admin/view/common/_require.html
index d5bcad6..44eb964 100644
--- a/extend/base/admin/view/common/_require.html
+++ b/extend/base/admin/view/common/_require.html
@@ -9,6 +9,9 @@
+
+
+
diff --git a/extend/base/admin/view/layout/default.html b/extend/base/admin/view/layout/default.html
index 73261b3..11b681d 100644
--- a/extend/base/admin/view/layout/default.html
+++ b/extend/base/admin/view/layout/default.html
@@ -17,7 +17,13 @@
IS_SUPER_ADMIN: "{$isSuperAdmin|default='false'}",
VERSION: "{$version|default='1.0.0'}",
CSRF_TOKEN: "{:token()}",
- PAGE_KEY_NAME:'{$pageKeyName|default=$Request.url}'
+ PAGE_KEY_NAME:'{$pageKeyName|default=$Request.url}',
+ // 静态资源根路径(与 __STATIC__ 模板替换一致,OSS 部署时指向 OSS),
+ // 供 JS 内部动态拼接静态资源地址的组件使用(tagInput/propertyInput/tableData 等)
+ STATIC: "__STATIC__",
+ // 静态资源版本键,与 _require.html 中 js/css 的 ?t= 参数同源,
+ // 保证动态请求的模板与引入的 js/css 缓存版本一致
+ STATIC_VERSION: "{:get_site_version_key()}"
};
var PATH_CONFIG = {
diff --git a/public/static/plugs/lay-module/propertyInput/propertyInput.js b/public/static/plugs/lay-module/propertyInput/propertyInput.js
index d109c1f..96d258b 100644
--- a/public/static/plugs/lay-module/propertyInput/propertyInput.js
+++ b/public/static/plugs/lay-module/propertyInput/propertyInput.js
@@ -1,30 +1,51 @@
(function () {
- const propertyInputCss = '/static/plugs/lay-module/propertyInput/propertyInput.css';
- const propertyInputHtml = '/static/plugs/lay-module/propertyInput/propertyInput.html';
+ // 组件模板懒加载:首次 render 时才异步请求,同页多实例共享一次请求;
+ // 路径与版本跟随页面注入的 CONFIG.STATIC / CONFIG.STATIC_VERSION,
+ // 与 _require.html 中 js/css 的缓存键保持一致;失败不缓存,下次 render 重试。
+ // 样式 propertyInput.css 已改为在 _require.html 中直接引入,不再由 JS 注入。
+ var propertyInputTemplatePromise = null;
- var propertyInput = function () {
- $(function () {
- var cssElement = document.createElement('link');
-
- cssElement.setAttribute('rel', 'stylesheet');
-
- cssElement.setAttribute('href', propertyInputCss);
-
- document.body.appendChild(cssElement);
- });
- };
- var propertyInputTemplate = '';
-
- $.ajax({
- type: "get",
- url: propertyInputHtml,
- cache: true,
- async: false,
- success: function (template) {
- propertyInputTemplate = template;
+ function loadPropertyInputTemplate() {
+ if (propertyInputTemplatePromise !== null) {
+ return propertyInputTemplatePromise;
}
- });
+ var config = window.CONFIG || {};
+ var staticRoot = config.STATIC || '/static';
+ var version = config.STATIC_VERSION || config.VERSION || '';
+ var url = staticRoot + '/plugs/lay-module/propertyInput/propertyInput.html?t=' + version;
+ var deferred = $.Deferred();
+
+ $.ajax({
+ type: 'get',
+ url: url,
+ cache: true,
+ dataType: 'text'
+ }).done(function (template) {
+ if ($.trim(template)) {
+ deferred.resolve(template);
+ } else {
+ deferred.reject('模板内容为空');
+ }
+ }).fail(function (xhr) {
+ deferred.reject(xhr);
+ });
+
+ propertyInputTemplatePromise = deferred.promise();
+ propertyInputTemplatePromise.fail(function (reason) {
+ console.error('propertyInput 模板加载失败: ' + url, reason);
+ var ua = window.UA_ADMIN || window.ua;
+ if (ua) {
+ ua.msg.error('propertyInput 组件初始化失败');
+ }
+ // 失败不缓存,下次 render 自动重试
+ propertyInputTemplatePromise = null;
+ });
+
+ return propertyInputTemplatePromise;
+ }
+
+ var propertyInput = function () { };
propertyInput.prototype.render = function (elem, data) {
@@ -184,88 +205,88 @@
}
}
- app = new Vue({
- el: elem,
- data() {
- return {
- setting: options,
- value: '',
- listItem: [
+ return loadPropertyInputTemplate().then(function (template) {
+ return new Vue({
+ el: elem,
+ data() {
+ return {
+ setting: options,
+ value: '',
+ listItem: [
- ],
- originalValue: '',
- field: options.field,
- };
- },
+ ],
+ originalValue: '',
+ field: options.field,
+ };
+ },
- created() {
- if (this.setting.value) {
- this.originalValue = $.extend(true, [], this.setting.value);
- this.listItem = $.extend(true, [], this.setting.value);
- this.updateValue(this.listItem);
+ created() {
+ if (this.setting.value) {
+ this.originalValue = $.extend(true, [], this.setting.value);
+ this.listItem = $.extend(true, [], this.setting.value);
+ this.updateValue(this.listItem);
- if (this.listItem.length == 0) {
- this.onAddItem();
+ if (this.listItem.length == 0) {
+ this.onAddItem();
+ }
+ }
+
+ },
+ mounted() {
+ if (options.required == 1) {
+ $(this.$refs['propertyInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
+ }
+ },
+ template: template,
+
+ methods: {
+ onResetItem() {
+ this.listItem = $.extend(true, [], this.originalValue);
+ if (this.listItem.length == 0) {
+ this.onAddItem();
+ }
+
+ this.updateValue(this.listItem);
+ },
+ onAddItem() {
+
+ var emptyItem = {};
+
+ emptyItem.uid = ua.randdomString();
+
+ for (var i = 0; i < this.field.length; i++) {
+ emptyItem[this.field[i].key] = this.field[i].default;
+ }
+
+ this.listItem.push(emptyItem);
+
+ this.updateValue(this.listItem);
+ },
+ onItemChange(item, index, itemField, event) {
+ this.listItem[index][itemField.key] = event.target.value;
+
+ this.updateValue(this.listItem);
+ },
+ onItemDelete(item, index) {
+ if (this.listItem.length <= 1) {
+ this.listItem = [
+ {
+ name: '',
+ value: ''
+ }
+ ];
+ } else {
+ this.listItem.splice(index, 1);
+ }
+
+ this.updateValue(this.listItem);
+ },
+ updateValue(newValue) {
+ this.value = JSON.stringify(newValue);
}
}
-
- },
- mounted() {
- if (options.required == 1) {
- $(this.$refs['propertyInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
- }
- },
- template: propertyInputTemplate,
-
- methods: {
- onResetItem() {
- this.listItem = $.extend(true, [], this.originalValue);
- if (this.listItem.length == 0) {
- this.onAddItem();
- }
-
- this.updateValue(this.listItem);
- },
- onAddItem() {
-
- var emptyItem = {};
-
- emptyItem.uid = ua.randdomString();
-
- for (var i = 0; i < this.field.length; i++) {
- emptyItem[this.field[i].key] = this.field[i].default;
- }
-
- this.listItem.push(emptyItem);
-
- this.updateValue(this.listItem);
- },
- onItemChange(item, index, itemField, event) {
- this.listItem[index][itemField.key] = event.target.value;
-
- this.updateValue(this.listItem);
- },
- onItemDelete(item, index) {
- if (this.listItem.length <= 1) {
- this.listItem = [
- {
- name: '',
- value: ''
- }
- ];
- } else {
- this.listItem.splice(index, 1);
- }
-
- this.updateValue(this.listItem);
- },
- updateValue(newValue) {
- this.value = JSON.stringify(newValue);
- }
- }
+ });
});
-
- return app;
};
window.propertyInput = new propertyInput();
diff --git a/public/static/plugs/lay-module/tableData/tableData.js b/public/static/plugs/lay-module/tableData/tableData.js
index cf0f8e2..ce35bdd 100644
--- a/public/static/plugs/lay-module/tableData/tableData.js
+++ b/public/static/plugs/lay-module/tableData/tableData.js
@@ -1,29 +1,53 @@
(function () {
- const tableDataCss = '/static/plugs/lay-module/tableData/tableData.css';
- const tableDataHtml = '/static/plugs/lay-module/tableData/tableData.html';
+ // 组件模板懒加载:首次 render 时才异步请求,同页多实例共享一次请求;
+ // 路径与版本跟随页面注入的 CONFIG.STATIC / CONFIG.STATIC_VERSION,
+ // 与 _require.html 中 js/css 的缓存键保持一致;失败不缓存,下次 render 重试。
+ // 样式 tableData.css 已改为在 _require.html 中直接引入,不再由 JS 注入。
+ var tableDataTemplatePromise = null;
- var tableData = function () {
- $(function () {
- var cssElement = document.createElement('link');
- cssElement.setAttribute('rel', 'stylesheet');
- cssElement.setAttribute('href', tableDataCss);
- document.body.appendChild(cssElement);
- });
- };
- var tableDataTemplate = '';
-
- $.ajax({
- type: "get",
- url: tableDataHtml,
- cache: true,
- async: false,
- success: function (template) {
- tableDataTemplate = template;
+ function loadTableDataTemplate() {
+ if (tableDataTemplatePromise !== null) {
+ return tableDataTemplatePromise;
}
- });
+
+ var config = window.CONFIG || {};
+ var staticRoot = config.STATIC || '/static';
+ var version = config.STATIC_VERSION || config.VERSION || '';
+ var url = staticRoot + '/plugs/lay-module/tableData/tableData.html?t=' + version;
+ var deferred = $.Deferred();
+
+ $.ajax({
+ type: 'get',
+ url: url,
+ cache: true,
+ dataType: 'text'
+ }).done(function (template) {
+ if ($.trim(template)) {
+ deferred.resolve(template);
+ } else {
+ deferred.reject('模板内容为空');
+ }
+ }).fail(function (xhr) {
+ deferred.reject(xhr);
+ });
+
+ tableDataTemplatePromise = deferred.promise();
+ tableDataTemplatePromise.fail(function (reason) {
+ console.error('tableData 模板加载失败: ' + url, reason);
+ var ua = window.UA_ADMIN || window.ua;
+ if (ua) {
+ ua.msg.error('tableData 组件初始化失败');
+ }
+ // 失败不缓存,下次 render 自动重试
+ tableDataTemplatePromise = null;
+ });
+
+ return tableDataTemplatePromise;
+ }
+
+ var tableData = function () { };
tableData.prototype.render = function (elem, data) {
- var app;
var clienWidth, clientHeight;
clienWidth = '100%';
clientHeight = '100%';
@@ -65,123 +89,123 @@
options.className = 'layui-textarea';
}
- app = new Vue({
- el: elem,
- data() {
- return {
- setting: options,
- listSelected: [],
- value: ''
- };
- },
- watch: {
- listSelected(value) {
+ return loadTableDataTemplate().then(function (template) {
+ return new Vue({
+ el: elem,
+ data() {
+ return {
+ setting: options,
+ listSelected: [],
+ value: ''
+ };
+ },
+ watch: {
+ listSelected(value) {
- var valueList = value.map(itemValue => itemValue[valueField]);
- var valueStr = valueList.join(',');
- if (options.selectType == 'checkbox') {
- if (options.trim == 0) {
- valueStr = ',' + valueStr + ',';
- }
- }
- this.value = valueStr;
- }
- },
- computed: {
- listSelectedShow() {
- if (this.setting.fieldName.indexOf('|') < 0) {
- return this.listSelected.map(
- (item) => {
- item['_select_show'] = ua.dataGet(item, this.setting.fieldName);
- return item;
+ var valueList = value.map(itemValue => itemValue[valueField]);
+ var valueStr = valueList.join(',');
+ if (options.selectType == 'checkbox') {
+ if (options.trim == 0) {
+ valueStr = ',' + valueStr + ',';
}
- );
- }
-
- var fieldNameList = this.setting.fieldName.split('|');
- return this.listSelected.map(item => {
- var showText = '';
- fieldNameList.forEach(fieldName => {
- showText += ua.dataGet(item, fieldName) + ' ';
- });
- item['_select_show'] = showText;
-
- return item;
- });
- },
- },
- created() {
- this.value = options.selectValue;
- if (typeof this.value != 'string') {
- this.value = this.value.toString();
- }
- var valueLength = this.value.split(',').length;
- loading.show();
- $.get(options.index, {
- page: 1,
- limit: valueLength,
- filter: JSON.stringify({ [options.valueField]: this.value }),
- op: JSON.stringify({ [options.valueField]: 'in' }),
- group: options.valueField
- }, (result) => {
- loading.hide();
- this.listSelected = result.data;
- });
-
- },
- mounted() {
- if (options.required == 1) {
- $(this.$refs['tableData']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
- }
- },
- template: tableDataTemplate,
-
- methods: {
- openSelectPage() {
-
- if (options.readonly == 1) {
- return false;
- }
-
- var selectedIds = this.listSelected.map(item => item.id);
- var index = layer.open({
- title: '选择数据',
- type: 2,
- area: [options.width, options.height],
- content: options.selectIndex + '&selectedIds=' + selectedIds.join(','),
- maxmin: true,
- moveOut: true,
- shadeClose: true,
- success: (layero, index) => {
- window[options.selectConfirmCallback] = (data) => {
- data.forEach(dataItem => {
-
- if (options.selectType == 'radio') {
- this.listSelected = [];
- }
- var itemFind = this.listSelected.find(itemSelect => itemSelect[valueField] == dataItem[valueField]);
- if (itemFind == undefined) {
- this.listSelected.push(dataItem);
- }
- });
- this.$forceUpdate();
- layer.close(index);
- };
- },
- end: function () {
- index = null;
- window[options.selectConfirmCallback] = undefined;
}
+ this.value = valueStr;
+ }
+ },
+ computed: {
+ listSelectedShow() {
+ if (this.setting.fieldName.indexOf('|') < 0) {
+ return this.listSelected.map(
+ (item) => {
+ item['_select_show'] = ua.dataGet(item, this.setting.fieldName);
+ return item;
+ }
+ );
+ }
+
+ var fieldNameList = this.setting.fieldName.split('|');
+ return this.listSelected.map(item => {
+ var showText = '';
+ fieldNameList.forEach(fieldName => {
+ showText += ua.dataGet(item, fieldName) + ' ';
+ });
+ item['_select_show'] = showText;
+
+ return item;
+ });
+ },
+ },
+ created() {
+ this.value = options.selectValue;
+ if (typeof this.value != 'string') {
+ this.value = this.value.toString();
+ }
+ var valueLength = this.value.split(',').length;
+ loading.show();
+ $.get(options.index, {
+ page: 1,
+ limit: valueLength,
+ filter: JSON.stringify({ [options.valueField]: this.value }),
+ op: JSON.stringify({ [options.valueField]: 'in' }),
+ group: options.valueField
+ }, (result) => {
+ loading.hide();
+ this.listSelected = result.data;
});
},
- removeItem(item, index) {
- this.listSelected.splice(index, 1);
- }
- }
- });
+ mounted() {
+ if (options.required == 1) {
+ $(this.$refs['tableData']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
+ }
+ },
+ template: template,
- return app;
+ methods: {
+ openSelectPage() {
+
+ if (options.readonly == 1) {
+ return false;
+ }
+
+ var selectedIds = this.listSelected.map(item => item.id);
+ var index = layer.open({
+ title: '选择数据',
+ type: 2,
+ area: [options.width, options.height],
+ content: options.selectIndex + '&selectedIds=' + selectedIds.join(','),
+ maxmin: true,
+ moveOut: true,
+ shadeClose: true,
+ success: (layero, index) => {
+ window[options.selectConfirmCallback] = (data) => {
+ data.forEach(dataItem => {
+
+ if (options.selectType == 'radio') {
+ this.listSelected = [];
+ }
+ var itemFind = this.listSelected.find(itemSelect => itemSelect[valueField] == dataItem[valueField]);
+ if (itemFind == undefined) {
+ this.listSelected.push(dataItem);
+ }
+ });
+ this.$forceUpdate();
+ layer.close(index);
+ };
+ },
+ end: function () {
+ index = null;
+ window[options.selectConfirmCallback] = undefined;
+ }
+ });
+
+ },
+ removeItem(item, index) {
+ this.listSelected.splice(index, 1);
+ }
+ }
+ });
+ });
};
window.tableData = new tableData();
diff --git a/public/static/plugs/lay-module/tagInput/tagInput.js b/public/static/plugs/lay-module/tagInput/tagInput.js
index 25390e6..48525f0 100644
--- a/public/static/plugs/lay-module/tagInput/tagInput.js
+++ b/public/static/plugs/lay-module/tagInput/tagInput.js
@@ -1,30 +1,51 @@
(function () {
- const tagInputCss = '/static/plugs/lay-module/tagInput/tagInput.css';
- const tagInputHtml = '/static/plugs/lay-module/tagInput/tagInput.html';
+ // 组件模板懒加载:首次 render 时才异步请求,同页多实例共享一次请求;
+ // 路径与版本跟随页面注入的 CONFIG.STATIC / CONFIG.STATIC_VERSION,
+ // 与 _require.html 中 js/css 的缓存键保持一致;失败不缓存,下次 render 重试。
+ // 样式 tagInput.css 已改为在 _require.html 中直接引入,不再由 JS 注入。
+ var tagInputTemplatePromise = null;
- var tagInput = function () {
- $(function () {
- var cssElement = document.createElement('link');
-
- cssElement.setAttribute('rel', 'stylesheet');
-
- cssElement.setAttribute('href', tagInputCss);
-
- document.body.appendChild(cssElement);
- });
- };
- var tagInputTemplate = '';
-
- $.ajax({
- type: "get",
- url: tagInputHtml,
- cache: true,
- async: false,
- success: function (template) {
- tagInputTemplate = template;
+ function loadTagInputTemplate() {
+ if (tagInputTemplatePromise !== null) {
+ return tagInputTemplatePromise;
}
- });
+ var config = window.CONFIG || {};
+ var staticRoot = config.STATIC || '/static';
+ var version = config.STATIC_VERSION || config.VERSION || '';
+ var url = staticRoot + '/plugs/lay-module/tagInput/tagInput.html?t=' + version;
+ var deferred = $.Deferred();
+
+ $.ajax({
+ type: 'get',
+ url: url,
+ cache: true,
+ dataType: 'text'
+ }).done(function (template) {
+ if ($.trim(template)) {
+ deferred.resolve(template);
+ } else {
+ deferred.reject('模板内容为空');
+ }
+ }).fail(function (xhr) {
+ deferred.reject(xhr);
+ });
+
+ tagInputTemplatePromise = deferred.promise();
+ tagInputTemplatePromise.fail(function (reason) {
+ console.error('tagInput 模板加载失败: ' + url, reason);
+ var ua = window.UA_ADMIN || window.ua;
+ if (ua) {
+ ua.msg.error('tagInput 组件初始化失败');
+ }
+ // 失败不缓存,下次 render 自动重试
+ tagInputTemplatePromise = null;
+ });
+
+ return tagInputTemplatePromise;
+ }
+
+ var tagInput = function () { };
tagInput.prototype.render = function (elem, data) {
@@ -35,81 +56,79 @@
var options = $.extend(defaultOption, data);
-
-
- app = new Vue({
- el: elem,
- data() {
- return {
- setting: options,
- value: '',
- inputValue: '',
- inputWidth: 100,
- inputValuePreview: '',
- listTag: []
- };
- },
- watch: {
- inputValue(value) {
-
- this.inputValuePreview = value;
- this.updateInputWidth();
+ return loadTagInputTemplate().then(function (template) {
+ return new Vue({
+ el: elem,
+ data() {
+ return {
+ setting: options,
+ value: '',
+ inputValue: '',
+ inputWidth: 100,
+ inputValuePreview: '',
+ listTag: []
+ };
},
- listTag(value) {
- this.value = value.join(',');
- }
- },
- created() {
- if (options.value.length > 0) {
- this.listTag = options.value.split(',');
+ watch: {
+ inputValue(value) {
- }
+ this.inputValuePreview = value;
+ this.updateInputWidth();
+ },
+ listTag(value) {
+ this.value = value.join(',');
+ }
+ },
+ created() {
+ if (options.value.length > 0) {
+ this.listTag = options.value.split(',');
- },
- mounted() {
- if (options.required == 1) {
- $(this.$refs['tagInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
- }
- },
- template: tagInputTemplate,
+ }
- methods: {
- onInputConfirm(e) {
+ },
+ mounted() {
+ if (options.required == 1) {
+ $(this.$refs['tagInput']).closest('.layui-form-item').children('.layui-form-label').addClass('required');
+ }
+ },
+ template: template,
- if (e) e.preventDefault();
+ methods: {
+ onInputConfirm(e) {
- if ($.trim(this.inputValue).length == 0) {
+ if (e) e.preventDefault();
+
+ if ($.trim(this.inputValue).length == 0) {
+ return false;
+ }
+
+ this.listTag.push(this.inputValue);
+ this.inputValue = '';
return false;
+ },
+ onContainerClick() {
+ $(this.$refs['tagInputMain']).focus();
+ },
+ onInputChange(e) {
+
+ var cvalue = $(e.target).val();
+ this.inputValuePreview = cvalue;
+
+ },
+ updateInputWidth() {
+ var width = $(this.$refs['preshow']).width();
+
+ if (width < 100) {
+ width = 100;
+ }
+ this.inputWidth = width + 60;
+ },
+ removeItem(item, index) {
+ this.listTag.splice(index, 1);
}
-
- this.listTag.push(this.inputValue);
- this.inputValue = '';
- return false;
- },
- onContainerClick() {
- $(this.$refs['tagInputMain']).focus();
- },
- onInputChange(e) {
-
- var cvalue = $(e.target).val();
- this.inputValuePreview = cvalue;
-
- },
- updateInputWidth() {
- var width = $(this.$refs['preshow']).width();
-
- if (width < 100) {
- width = 100;
- }
- this.inputWidth = width + 60;
- },
- removeItem(item, index) {
- this.listTag.splice(index, 1);
}
- }
+ });
});
-
- return app;
};
window.tagInput = new tagInput();