家谱现有接口调试50%

This commit is contained in:
rain
2026-07-09 17:29:25 +08:00
commit 6050508144
262 changed files with 63354 additions and 0 deletions
+314
View File
@@ -0,0 +1,314 @@
(function (root, factory) {
// 相册模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.AlbumPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.AlbumPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
var selectedAlbumId = '';
function normalizeList(data) {
// 相册接口列表响应兼容数组、rows、records、list、data。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 相册名称和照片说明进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-album-page], [data-promo-album-page]');
return getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
getQueryParam(search, 'id') ||
'';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value, fallback) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : fallback;
}
function buildAlbumBody(values) {
// AlbumBody 来自 APP.openapi.jsonalbumName 必填。
var source = values || {};
return {
albumName: String(source.albumName || '').trim(),
albumDesc: trimOrUndefined(source.albumDesc),
coverOssId: toNumber(source.coverOssId),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function buildPhotoBody(values) {
// AlbumPhotoBody 来自 APP.openapi.jsonossId 必填。
var source = values || {};
return {
ossId: toNumber(source.ossId),
photoTitle: trimOrUndefined(source.photoTitle),
photoDesc: trimOrUndefined(source.photoDesc),
photographer: trimOrUndefined(source.photographer),
shootTime: trimOrUndefined(source.shootTime),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function getAlbumId(item) {
return pick(item, ['albumId', 'id'], '');
}
function buildAlbumRow(item) {
var albumId = getAlbumId(item);
var name = pick(item, ['albumName', 'name'], '未命名相册');
var photoCount = pick(item, ['photoCount', 'photos'], '0');
var desc = pick(item, ['albumDesc', 'description'], '暂无说明');
return '<button class="module-row album-row" type="button" data-album-id="' + escapeHtml(albumId) + '">' +
'<div><h3>' + escapeHtml(name) + '</h3><p>' + escapeHtml(photoCount) + ' 张照片 · ' + escapeHtml(desc) + '</p></div>' +
'<span class="pill">管理</span></button>';
}
function buildPhotoRow(item) {
var title = pick(item, ['photoTitle', 'title'], '未命名照片');
var desc = pick(item, ['photoDesc', 'description'], '暂无说明');
var photographer = pick(item, ['photographer'], '未记录拍摄人');
return '<div class="module-row album-photo-row"><div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(desc) + ' · ' + escapeHtml(photographer) + '</p></div><span class="pill">照片</span></div>';
}
function renderAlbums(items) {
var container = query('[data-album-list], [data-promo-album-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无相册</div>';
return;
}
container.innerHTML = list.map(buildAlbumRow).join('');
}
function renderPhotos(items) {
var container = query('[data-album-photo-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无照片</div>';
return;
}
container.innerHTML = list.map(buildPhotoRow).join('');
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
async function loadAlbums() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
if (!api || !genealogyId) return;
try {
renderAlbums(await api.albums(genealogyId));
} catch (error) {
showMessage(error.message || '相册加载失败');
}
}
async function loadPhotos(albumId) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
if (!api || !genealogyId || !albumId) return;
selectedAlbumId = albumId;
try {
renderPhotos(await api.albumPhotos(genealogyId, albumId));
} catch (error) {
showMessage(error.message || '照片加载失败');
}
}
async function submitAlbum(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var body = buildAlbumBody(getFormValues(form));
if (!api || !genealogyId) {
showMessage('请从具体家谱进入相册管理');
return;
}
if (!body.albumName) {
showMessage('请填写相册名称');
return;
}
try {
if (selectedAlbumId) {
await api.updateAlbum(genealogyId, selectedAlbumId, body);
} else {
await api.createAlbum(genealogyId, body);
}
form.reset();
selectedAlbumId = '';
showMessage('相册已保存');
loadAlbums();
} catch (error) {
showMessage(error.message || '保存相册失败');
}
}
async function submitPhoto(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var body = buildPhotoBody(getFormValues(form));
if (!api || !genealogyId || !selectedAlbumId) {
showMessage('请先选择相册');
return;
}
if (!body.ossId) {
showMessage('请填写照片 OSS ID');
return;
}
try {
await api.createAlbumPhoto(genealogyId, selectedAlbumId, body);
form.reset();
showMessage('照片已添加');
loadPhotos(selectedAlbumId);
} catch (error) {
showMessage(error.message || '添加照片失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('click', function (event) {
var albumButton = event.target.closest('[data-album-id]');
if (!albumButton) return;
event.preventDefault();
loadPhotos(albumButton.getAttribute('data-album-id'));
});
documentRef.addEventListener('submit', function (event) {
var albumForm = event.target.closest('[data-album-form]');
var photoForm = event.target.closest('[data-album-photo-form]');
if (albumForm) {
event.preventDefault();
submitAlbum(albumForm);
}
if (photoForm) {
event.preventDefault();
submitPhoto(photoForm);
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadAlbums();
}
return {
normalizeList: normalizeList,
buildAlbumBody: buildAlbumBody,
buildPhotoBody: buildPhotoBody,
buildAlbumRow: buildAlbumRow,
init: init
};
});
+449
View File
@@ -0,0 +1,449 @@
(function (root, factory) {
// 同一份接口客户端同时支持浏览器页面和 Node 测试环境。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GenealogyApi = factory(root);
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var DEFAULT_BASE_URL = 'http://test-genealogy-api.ddxcjp.cn';
var DEFAULT_CLIENT_ID = 'ced7e5f0498645c6ec642dcf450b036f';
var DEFAULT_TENANT_ID = '000000';
var DEFAULT_TOKEN_KEY = 'genealogy_auth_token';
var DEFAULT_TOKEN_HEADER_NAME = 'Authorization';
function loadNodeModule(path) {
if (typeof require !== 'function') return null;
try {
return require(path);
} catch (error) {
return null;
}
}
function getConfigApi() {
var configFactory;
if (root.GenealogyConfig) return root.GenealogyConfig;
configFactory = loadNodeModule('../../config.js');
return configFactory ? configFactory(root) : null;
}
function getStorageUtil() {
return root.StorageUtil || loadNodeModule('../../utils/StorageUtil.js');
}
function getRequestUtil() {
return root.RequestUtil || loadNodeModule('../../utils/RequestUtil.js');
}
function getStorage(store) {
if (store) return store;
try {
return root.localStorage;
} catch (error) {
return null;
}
}
function getTokenFromResponse(data) {
// 登录响应可能使用不同 token 字段,这里统一收敛为本地登录票据。
if (!data) return '';
return data.token || data.accessToken || data.tokenValue || '';
}
function ApiError(message, options) {
this.name = 'ApiError';
this.message = message || '接口请求失败';
this.status = options && options.status;
this.code = options && options.code;
this.data = options && options.data;
}
ApiError.prototype = Object.create(Error.prototype);
ApiError.prototype.constructor = ApiError;
function createUnavailableMethod(name) {
return function () {
var error = new Error('PC 接口文档未提供该业务接口:' + name);
error.code = 'PC_API_NOT_AVAILABLE';
throw error;
};
}
function createFormData(fileOrFormData) {
var FormDataCtor = root.FormData;
var formData;
if (FormDataCtor && fileOrFormData instanceof FormDataCtor) return fileOrFormData;
if (!FormDataCtor) throw new ApiError('当前环境不支持文件上传');
formData = new FormDataCtor();
formData.append('file', fileOrFormData);
return formData;
}
function createChunkFormData(body) {
var FormDataCtor = root.FormData;
var source = body || {};
var formData;
if (FormDataCtor && body instanceof FormDataCtor) return body;
if (!FormDataCtor) throw new ApiError('当前环境不支持文件上传');
formData = new FormDataCtor();
formData.append('uploadId', source.uploadId);
formData.append('chunkIndex', source.chunkIndex);
formData.append('chunkMd5', source.chunkMd5);
formData.append('file', source.file);
return formData;
}
function createClient(options) {
var settings = options || {};
var configApi = getConfigApi();
var config = configApi && configApi.getConfig ? configApi.getConfig() : {};
var storageUtil = getStorageUtil();
var requestUtil = getRequestUtil();
var store = getStorage(settings.tokenStore || settings.storage);
var clientId = settings.clientId || config.clientId || DEFAULT_CLIENT_ID;
var tenantId = settings.tenantId || config.tenantId || DEFAULT_TENANT_ID;
var tokenKey = settings.tokenKey || config.tokenKey || DEFAULT_TOKEN_KEY;
var tokenHeaderName = settings.tokenHeaderName || config.tokenHeaderName || DEFAULT_TOKEN_HEADER_NAME;
var baseUrl = settings.baseUrl || config.apiBaseUrl || DEFAULT_BASE_URL;
var requester;
if (!requestUtil || !requestUtil.createRequester) {
throw new ApiError('缺少 RequestUtil.createRequester 公共请求工具');
}
function getToken() {
return storageUtil && storageUtil.read ? storageUtil.read(store, tokenKey) || '' : '';
}
function setToken(token) {
if (token && storageUtil && storageUtil.write) storageUtil.write(store, tokenKey, token);
}
function clearToken() {
if (storageUtil && storageUtil.remove) storageUtil.remove(store, tokenKey);
}
requester = requestUtil.createRequester({
baseUrl: baseUrl,
clientId: clientId,
tokenHeaderName: tokenHeaderName,
getToken: getToken,
fetchImpl: settings.fetchImpl || root.fetch
});
function request(method, path, requestOptions) {
return requester(method, path, requestOptions || {});
}
function withTenant(body) {
return Object.assign({
tenantId: tenantId,
clientId: clientId
}, body || {});
}
async function login(body) {
var data = await request('POST', '/genealogy/pc/auth/login', {
auth: false,
body: Object.assign({
grantType: 'password'
}, withTenant(body))
});
setToken(getTokenFromResponse(data));
return data;
}
async function register(body) {
var data = await request('POST', '/genealogy/pc/auth/register', {
auth: false,
body: Object.assign({
grantType: 'password',
registerSource: 'PC'
}, withTenant(body))
});
setToken(getTokenFromResponse(data));
return data;
}
async function loginBySms(body) {
var data = await request('POST', '/genealogy/pc/auth/login/sms', {
auth: false,
body: Object.assign({
grantType: 'sms'
}, withTenant(body))
});
setToken(getTokenFromResponse(data));
return data;
}
function sendSmsCode(body) {
return request('POST', '/genealogy/pc/auth/sms/code', {
auth: false,
body: Object.assign({
grantType: 'sms'
}, withTenant(body))
});
}
function captchaRequire(body) {
var source = body || {};
return request('GET', '/captcha/require', {
auth: false,
query: {
tenantId: source.tenantId || tenantId,
clientId: source.clientId || clientId,
sceneCode: source.sceneCode,
subject: source.subject
}
});
}
function buildApiUrl(path, query) {
if (requestUtil.joinUrl && requestUtil.appendQuery) {
return requestUtil.appendQuery(requestUtil.joinUrl(baseUrl, path), query);
}
return baseUrl + path;
}
var client = {
clientId: clientId,
tenantId: tenantId,
tokenKey: tokenKey,
getToken: getToken,
setToken: setToken,
clearToken: clearToken,
request: request,
buildApiUrl: buildApiUrl,
get: function (path, query) {
return request('GET', path, { query: query });
},
post: function (path, body, reqOptions) {
return request('POST', path, Object.assign({}, reqOptions || {}, { body: body }));
},
put: function (path, body, reqOptions) {
return request('PUT', path, Object.assign({}, reqOptions || {}, { body: body }));
},
delete: function (path, reqOptions) {
return request('DELETE', path, reqOptions || {});
},
login: login,
register: register,
sendSmsCode: sendSmsCode,
loginBySms: loginBySms,
smsLogin: loginBySms,
getProfile: function () {
return request('GET', '/genealogy/pc/auth/profile');
},
currentProfile: function () {
return request('GET', '/genealogy/pc/auth/profile');
},
updateProfile: function (body) {
return request('PUT', '/genealogy/pc/auth/profile', { body: body });
},
changePassword: function (body) {
return request('PUT', '/genealogy/pc/auth/password', { body: body });
},
resetPassword: function (body) {
return request('PUT', '/genealogy/pc/auth/password/reset', {
auth: false,
body: Object.assign({
tenantId: tenantId
}, body || {})
});
},
changePhone: function (body) {
return request('PUT', '/genealogy/pc/auth/phone', { body: body });
},
deactivateAccount: async function (body) {
var data = await request('POST', '/genealogy/pc/auth/account/deactivate', { body: body });
clearToken();
return data;
},
logout: async function () {
var data = await request('DELETE', '/genealogy/pc/auth/logout');
clearToken();
return data;
},
uploadFile: function (fileOrFormData) {
return request('POST', '/genealogy/pc/files/upload', {
body: createFormData(fileOrFormData)
});
},
initResumableUpload: function (body) {
return request('POST', '/genealogy/pc/files/resumable/init', { body: body });
},
uploadChunk: function (body) {
return request('POST', '/genealogy/pc/files/resumable/chunk', {
body: createChunkFormData(body)
});
},
uploadResumableChunk: function (body) {
return this.uploadChunk(body);
},
completeResumableUpload: function (body) {
return request('POST', '/genealogy/pc/files/resumable/complete', { body: body });
},
bindFileReference: function (body) {
return request('POST', '/genealogy/pc/files/reference', { body: body });
},
releaseFileReference: function (query) {
return request('DELETE', '/genealogy/pc/files/reference', { query: query });
},
getRegionChildren: function (parentCode) {
return request('GET', '/genealogy/region/children', {
query: {
parentCode: parentCode
}
});
},
regionChildren: function (parentCode) {
return this.getRegionChildren(parentCode);
},
getRegionPath: function (regionCode) {
return request('GET', '/genealogy/region/path/' + encodeURIComponent(regionCode));
},
regionPath: function (regionCode) {
return this.getRegionPath(regionCode);
},
searchRegions: function (query) {
return request('GET', '/genealogy/region/search', { query: query });
},
regionSearch: function (query) {
return this.searchRegions(query);
},
getRegion: function (regionCode) {
return request('GET', '/genealogy/region/' + encodeURIComponent(regionCode));
},
regionDetail: function (regionCode) {
return this.getRegion(regionCode);
},
captchaRequire: captchaRequire,
captchaRequirement: captchaRequire,
captchaChallenge: function (body) {
return request('POST', '/captcha/challenge', { auth: false, body: body });
},
captchaVerify: function (body) {
return request('POST', '/captcha/verify', { auth: false, body: body });
},
legacyCaptcha: function () {
return request('GET', '/auth/code', { auth: false });
}
};
// PC YAML 未提供这些业务 paths,保留方法名只用于阻止旧移动端路径继续发请求。
[
'listGenealogies',
'createGenealogy',
'publicGenealogies',
'myGenealogies',
'genealogyDetail',
'genealogyOverview',
'applyJoinGenealogy',
'myJoinApplies',
'pendingJoinApplies',
'auditJoinApply',
'cancelJoinApply',
'genealogyMembers',
'genealogyMemberOptions',
'updateGenealogyMember',
'removeGenealogyMember',
'leaveGenealogy',
'transferGenealogyOwner',
'articleCategories',
'articles',
'articleDetail',
'createArticle',
'updateArticle',
'feeds',
'feedsPage',
'feedDetail',
'createFeed',
'updateFeed',
'likeFeed',
'unlikeFeed',
'feedComments',
'feedCommentsPage',
'createFeedComment',
'deleteFeedComment',
'albums',
'createAlbum',
'updateAlbum',
'albumPhotos',
'createAlbumPhoto',
'ceremonies',
'ceremonyDetail',
'createCeremony',
'updateCeremony',
'ceremonyGifts',
'createCeremonyGift',
'meritRecords',
'createMeritRecord',
'growthRecords',
'growthRecordDetail',
'createGrowthRecord',
'updateGrowthRecord',
'memos',
'memoDetail',
'createMemo',
'updateMemo',
'vipPackages',
'vipOrders',
'createVipOrder',
'generationPoems',
'createGenerationPoem',
'updateGenerationPoem',
'previewGenerationPoems',
'saveGenerationPoemsBatch',
'lineageTree',
'lineagePersons',
'lineagePersonsPage',
'lineagePersonOptions',
'lineagePersonDetail',
'createLineagePerson',
'updateLineagePerson',
'deleteLineagePerson',
'addLineageRelation',
'notifications',
'markNotificationRead',
'markAllNotificationsRead',
'helpArticles',
'helpArticleDetail',
'promotions',
'feedbackList',
'submitFeedback'
].forEach(function (name) {
client[name] = createUnavailableMethod(name);
});
return client;
}
return {
DEFAULT_BASE_URL: DEFAULT_BASE_URL,
DEFAULT_CLIENT_ID: DEFAULT_CLIENT_ID,
DEFAULT_TENANT_ID: DEFAULT_TENANT_ID,
TOKEN_KEY: DEFAULT_TOKEN_KEY,
ApiError: ApiError,
createClient: createClient,
defaultClient: createClient()
};
});
+297
View File
@@ -0,0 +1,297 @@
(function (root, factory) {
// 谱文模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.ArticlePages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.ArticlePages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 通用列表响应兼容数组、rows、records、list、data。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 标题和摘要进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-article-page], [data-article-edit-page], [data-article-detail-page], [data-content-page]');
return getQueryParam(search, 'genealogyId') ||
getQueryParam(search, 'familyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
getQueryParam(search, 'id') ||
'';
}
function getCurrentArticleId() {
var search = root.location && root.location.search;
return getQueryParam(search, 'articleId') || getQueryParam(search, 'id') || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value, fallback) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : fallback;
}
function formatStatus(status) {
var value = String(status === undefined || status === null ? '' : status);
if (value === '0' || value === 'published') return '已发布';
if (value === '1' || value === 'draft') return '草稿';
return value || '未知';
}
function buildArticleBody(values) {
// ArticleBody 来自 APP.openapi.json,标题和正文为核心必填。
var source = values || {};
return {
categoryId: toNumber(source.categoryId),
articleTitle: String(source.articleTitle || '').trim(),
articleSummary: trimOrUndefined(source.articleSummary),
coverOssId: toNumber(source.coverOssId),
articleContent: String(source.articleContent || '').trim(),
authorName: trimOrUndefined(source.authorName),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function getArticleId(item) {
return pick(item, ['articleId', 'id'], '');
}
function buildArticleRow(item, genealogyId) {
var articleId = getArticleId(item);
var title = pick(item, ['articleTitle', 'title'], '未命名谱文');
var category = pick(item, ['categoryName', 'categoryTitle', 'typeName'], '谱文');
var status = formatStatus(pick(item, ['status'], '0'));
var updateTime = pick(item, ['updateTime', 'publishTime', 'createTime'], '未记录时间');
return '<a class="module-row article-row" href="article-detail.html?id=' + encodeURIComponent(articleId) + '&genealogyId=' + encodeURIComponent(genealogyId || '') + '">' +
'<div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(category) + ' · ' + escapeHtml(status) + ' · ' + escapeHtml(updateTime) + '</p></div>' +
'<span class="pill">查看</span></a>';
}
function buildCategoryOption(item) {
var categoryId = pick(item, ['categoryId', 'id'], '');
var name = pick(item, ['categoryName', 'name', 'title'], '未命名分类');
return '<option value="' + escapeHtml(categoryId) + '">' + escapeHtml(name) + '</option>';
}
function renderArticles(items, genealogyId) {
var container = query('[data-article-list], [data-recent-content]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无谱文内容</div>';
return;
}
container.innerHTML = list.map(function (item) {
return buildArticleRow(item, genealogyId);
}).join('');
}
function renderCategories(items) {
var select = query('[data-article-category]');
var list = normalizeList(items);
if (!select) return;
select.innerHTML = '<option value="">请选择分类</option>' + list.map(buildCategoryOption).join('');
}
function renderArticleDetail(article) {
var source = article || {};
var title = query('[data-article-title]');
var summary = query('[data-article-summary]');
var meta = query('[data-article-meta]');
var content = query('[data-article-content]');
if (title) title.textContent = pick(source, ['articleTitle', 'title'], '未命名谱文');
if (summary) summary.textContent = pick(source, ['articleSummary', 'summary'], '暂无摘要');
if (meta) {
meta.innerHTML = '<span>' + escapeHtml(pick(source, ['categoryName'], '谱文')) + '</span><span>' + escapeHtml(pick(source, ['authorName'], '佚名')) + '</span><span>' + escapeHtml(pick(source, ['updateTime', 'publishTime', 'createTime'], '未记录时间')) + '</span>';
}
if (content) content.innerHTML = pick(source, ['articleContent', 'content'], '<p>暂无正文</p>');
}
function fillArticleForm(article) {
var source = article || {};
queryAll('[name]').forEach(function (field) {
var value = pick(source, [field.name], '');
if (value !== '') field.value = value;
});
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
async function loadArticles() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var articleId = getCurrentArticleId();
if (!api || !genealogyId) return;
try {
if (query('[data-article-list], [data-recent-content]')) {
renderArticles(await api.articles(genealogyId), genealogyId);
}
if (query('[data-article-category]')) {
renderCategories(await api.articleCategories(genealogyId));
}
if (articleId && query('[data-article-detail-page], [data-article-edit-page]')) {
if (query('[data-article-detail-page]')) {
renderArticleDetail(await api.articleDetail(genealogyId, articleId));
} else {
fillArticleForm(await api.articleDetail(genealogyId, articleId));
}
}
} catch (error) {
showMessage(error.message || '谱文数据加载失败');
}
}
async function submitArticle(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var articleId = getCurrentArticleId();
var body = buildArticleBody(getFormValues(form));
if (!api || !genealogyId) {
showMessage('请从具体家谱进入谱文编辑');
return;
}
if (!body.articleTitle || !body.articleContent) {
showMessage('请填写谱文标题和正文');
return;
}
try {
if (articleId) {
await api.updateArticle(genealogyId, articleId, body);
} else {
await api.createArticle(genealogyId, body);
}
showMessage('谱文已保存');
root.location.href = 'profile-article.html?genealogyId=' + encodeURIComponent(genealogyId);
} catch (error) {
showMessage(error.message || '保存谱文失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-article-form]');
if (!form) return;
event.preventDefault();
submitArticle(form);
});
}
function init() {
if (!documentRef) return;
bindActions();
loadArticles();
}
return {
normalizeList: normalizeList,
buildArticleBody: buildArticleBody,
buildArticleRow: buildArticleRow,
formatStatus: formatStatus,
init: init
};
});
+342
View File
@@ -0,0 +1,342 @@
(function (root, factory) {
// 认证页脚本同时给浏览器页面和 Node 测试使用。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.AuthPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.AuthPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function hashPassword(value) {
// 接口文档要求密码传 32 位 MD5;没有加载 md5.js 时保留原值,便于测试定位。
if (root.hex_md5) return root.hex_md5(value);
if (root.md5) return root.md5(value);
return value;
}
function buildLoginBody(values, hashFn) {
// 这里只组装页面字段,grantType、tenantId、clientId 由 api-client 统一补齐。
var hash = hashFn || hashPassword;
var body = {
phone: values.phone,
password: hash(values.password)
};
if (values.validToken) body.validToken = values.validToken;
return body;
}
function buildSmsLoginBody(values) {
// 短信登录接口只需要页面字段,grantType、tenantId、clientId 由 api-client 统一补齐。
var body = {
phone: values.phone,
smsCode: values.smsCode
};
if (values.validToken) body.validToken = values.validToken;
return body;
}
function buildRegisterBody(values, hashFn) {
// 注册验证码当前对应 validToken,可选字段只在有值时提交。
var hash = hashFn || hashPassword;
var body = {
phone: values.phone,
password: hash(values.password),
nickName: values.nickName || values.phone
};
if (values.validToken) body.validToken = values.validToken;
return body;
}
function buildPasswordResetBody(values, hashFn) {
// 找回密码接口使用 newPassword 字段,页面确认密码只在提交前校验,不传给后端。
var hash = hashFn || hashPassword;
return {
phone: values.phone,
smsCode: values.smsCode,
newPassword: hash(values.newPassword),
validToken: values.validToken || ''
};
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function getCaptchaScene(formType) {
// PC/H5 认证场景来自后台验证码配置,客户端 Key 为 web_pc。
var map = {
login: 'WEB_H5_LOGIN',
register: 'WEB_H5_REGISTER',
'password-reset': 'WEB_H5_FORGOT_PASSWORD'
};
return map[formType] || '';
}
function getFormCaptchaScene(form, formType) {
// 页面可通过 data-captcha-scene 显式声明后台配置的验证码场景。
var sceneCode = form && form.getAttribute && form.getAttribute('data-captcha-scene');
return sceneCode || getCaptchaScene(formType);
}
async function ensureCaptcha(form, sceneCode, subject) {
// 未配置 PC/H5 验证场景时不调用验证中心,也不伪造 validToken。
if (!sceneCode) return true;
// 验证适配层不存在时不阻塞测试环境;真实页面会加载 captcha-pages.js。
if (!root.CaptchaPages || !root.CaptchaPages.ensureToken) return true;
return Boolean(await root.CaptchaPages.ensureToken(form, {
sceneCode: sceneCode,
subject: subject
}));
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function readForm(form) {
// 页面通过 name 属性和接口字段对齐,避免按 placeholder 文案取值。
var values = {};
queryAll('input[name], textarea[name], select[name]', form).forEach(function (field) {
values[field.name] = String(field.value || '').trim();
});
return values;
}
function setBusy(button, busy) {
// 加载状态只切 class 和 aria,不在 JS 中写样式。
if (!button) return;
button.classList.toggle('is-loading', busy);
if ('disabled' in button) button.disabled = busy;
button.setAttribute('aria-busy', busy ? 'true' : 'false');
}
function showMessage(message) {
if (root.MessageUtil && root.MessageUtil.show) {
root.MessageUtil.show(message);
return;
}
if (root.console && root.console.warn) root.console.warn(message);
}
function requireValue(value, message) {
if (value) return true;
showMessage(message);
return false;
}
function bindSubmit(selector, handler) {
// 所有认证表单统一拦截 submit,避免链接跳转绕过接口请求。
var form = query(selector);
if (!form) return;
form.addEventListener('submit', function (event) {
event.preventDefault();
handler(form, query('[type="submit"]', form));
});
}
function setLoginMode(activeMode) {
// 登录方式切换只更新状态,具体样式由 login.css 控制。
queryAll('[data-login-mode-tab]').forEach(function (button) {
var isActive = button.getAttribute('data-login-mode-tab') === activeMode;
button.classList.toggle('is-active', isActive);
button.setAttribute('aria-selected', isActive ? 'true' : 'false');
});
queryAll('[data-login-mode-panel]').forEach(function (panel) {
var isActive = panel.getAttribute('data-login-mode-panel') === activeMode;
panel.hidden = !isActive;
});
}
async function submitLogin(form, button) {
// 登录成功后跳转地址由 HTML 的 data-success-url 控制,页面可单独调整。
var api = getApi();
var values = readForm(form);
if (!api) return;
if (!requireValue(values.phone, '请填写手机号')) return;
if (!requireValue(values.password, '请填写密码')) return;
if (!await ensureCaptcha(form, getFormCaptchaScene(form, 'login'), values.phone)) return;
values = readForm(form);
setBusy(button, true);
try {
await api.login(buildLoginBody(values));
root.location.href = form.getAttribute('data-success-url') || 'profile.html';
} catch (error) {
showMessage(error.message || '登录失败');
} finally {
setBusy(button, false);
}
}
async function submitSmsLogin(form, button) {
// PC 短信登录与密码登录共用 WEB_H5_LOGIN 场景,短信码由同页按钮发送。
var api = getApi();
var values = readForm(form);
if (!api) return;
if (!requireValue(values.phone, '请填写手机号')) return;
if (!requireValue(values.smsCode, '请填写短信验证码')) return;
if (!await ensureCaptcha(form, getFormCaptchaScene(form, 'login'), values.phone)) return;
values = readForm(form);
setBusy(button, true);
try {
await api.loginBySms(buildSmsLoginBody(values));
root.location.href = form.getAttribute('data-success-url') || 'profile.html';
} catch (error) {
showMessage(error.message || '短信登录失败');
} finally {
setBusy(button, false);
}
}
async function submitRegister(form, button) {
// 注册成功后默认进入创建家谱流程。
var api = getApi();
var values = readForm(form);
if (!api) return;
if (!requireValue(values.phone, '请填写手机号')) return;
if (!requireValue(values.password, '请填写密码')) return;
if (!await ensureCaptcha(form, getFormCaptchaScene(form, 'register'), values.phone)) return;
values = readForm(form);
setBusy(button, true);
try {
await api.register(buildRegisterBody(values));
root.location.href = form.getAttribute('data-success-url') || 'create-genealogy.html';
} catch (error) {
showMessage(error.message || '注册失败');
} finally {
setBusy(button, false);
}
}
async function sendCode(button) {
// 当前只接找回密码验证码;后续注册短信可复用 data-scene-code 扩展。
var api = getApi();
var form = button.closest('form');
var values = readForm(form);
var sceneCode = button.getAttribute('data-scene-code') || getFormCaptchaScene(form, 'password-reset');
if (!api) return;
if (!requireValue(values.phone, '请填写手机号')) return;
if (!await ensureCaptcha(form, sceneCode, values.phone)) return;
values = readForm(form);
setBusy(button, true);
try {
await api.sendSmsCode({
sceneCode: sceneCode,
phone: values.phone,
validToken: values.validToken || ''
});
showMessage('验证码已发送');
} catch (error) {
showMessage(error.message || '验证码发送失败');
} finally {
setBusy(button, false);
}
}
async function submitPasswordReset(form, button) {
// 前端先校验两次密码一致,再按接口字段提交重置请求。
var api = getApi();
var values = readForm(form);
if (!api) return;
if (!requireValue(values.phone, '请填写手机号')) return;
if (!requireValue(values.smsCode, '请填写验证码')) return;
if (!requireValue(values.newPassword, '请填写新密码')) return;
if (values.newPassword !== values.confirmPassword) {
showMessage('两次输入的新密码不一致');
return;
}
if (!await ensureCaptcha(form, getFormCaptchaScene(form, 'password-reset'), values.phone)) return;
values = readForm(form);
setBusy(button, true);
try {
await api.resetPassword(buildPasswordResetBody(values));
showMessage('密码已重设,请重新登录');
root.location.href = form.getAttribute('data-success-url') || 'login.html';
} catch (error) {
showMessage(error.message || '重设密码失败');
} finally {
setBusy(button, false);
}
}
function bindCodeButtons() {
queryAll('[data-api-send-code]').forEach(function (button) {
button.addEventListener('click', function (event) {
event.preventDefault();
sendCode(button);
});
});
}
function bindLoginModeTabs() {
queryAll('[data-login-mode-tab]').forEach(function (button) {
button.addEventListener('click', function () {
setLoginMode(button.getAttribute('data-login-mode-tab'));
});
});
}
function init() {
// 每个页面只会命中自己的 data-auth-form,不需要拆多个入口文件。
if (!documentRef) return;
bindSubmit('[data-auth-form="login"]', submitLogin);
bindSubmit('[data-auth-form="sms-login"]', submitSmsLogin);
bindSubmit('[data-auth-form="register"]', submitRegister);
bindSubmit('[data-auth-form="password-reset"]', submitPasswordReset);
bindLoginModeTabs();
bindCodeButtons();
}
return {
buildLoginBody: buildLoginBody,
buildSmsLoginBody: buildSmsLoginBody,
buildRegisterBody: buildRegisterBody,
buildPasswordResetBody: buildPasswordResetBody,
getCaptchaScene: getCaptchaScene,
getFormCaptchaScene: getFormCaptchaScene,
init: init
};
});
+261
View File
@@ -0,0 +1,261 @@
(function (root, factory) {
// 验证码适配层同时支持浏览器运行和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.CaptchaPages = factory(root);
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var DEFAULT_SCENE_CODE = 'WEB_H5_LOGIN';
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || root.document).querySelector(selector);
}
function showMessage(message) {
if (root.MessageUtil && root.MessageUtil.show) {
root.MessageUtil.show(message);
return;
}
if (root.console && root.console.warn) root.console.warn(message);
}
function buildChallengeBody(options, api) {
// 请求体字段严格对应 PC YAML 的 VerificationChallengeBody。
var settings = options || {};
return {
tenantId: settings.tenantId || api.tenantId,
clientId: settings.clientId || api.clientId,
sceneCode: settings.sceneCode || DEFAULT_SCENE_CODE,
subject: settings.subject || ''
};
}
function normalizeChallengeData(data) {
// TAC 需要 data.type、data.id 和图片字段;接口文档返回 captchaType、challengeId、payload。
var source = data || {};
var payload = source.payload || {};
return Object.assign({}, payload, {
type: source.captchaType || payload.type || 'SLIDER',
id: payload.id || source.challengeId,
challengeId: source.challengeId,
providerCode: source.providerCode || 'tianai',
captchaType: source.captchaType || payload.type || 'SLIDER'
});
}
function adaptChallengeResponse(response) {
var payload = response || {};
if (Number(payload.code) !== 200 || !payload.data) return payload;
return Object.assign({}, payload, {
data: normalizeChallengeData(payload.data)
});
}
function buildVerifyBody(requestData, context, api) {
// requestData 是 TAC 拖动完成后的轨迹数据;context 保存本次挑战的接口字段。
var settings = context || {};
var source = requestData || {};
return {
tenantId: settings.tenantId || api.tenantId,
clientId: settings.clientId || api.clientId,
sceneCode: settings.sceneCode || DEFAULT_SCENE_CODE,
subject: settings.subject || '',
challengeId: settings.challengeId || source.challengeId || source.id,
providerCode: settings.providerCode || 'tianai',
captchaType: settings.captchaType || 'SLIDER',
payload: {
id: source.id,
data: source.data || {}
}
};
}
function normalizeVerifyResponse(response) {
// TAC 只看 code 是否为 200;接口通过 passed 表示业务验证结果。
var payload = response || {};
if (Number(payload.code) === 200 && payload.data && payload.data.passed === false) {
return Object.assign({}, payload, {
code: 4001,
msg: payload.data.message || payload.msg || '验证失败'
});
}
return payload;
}
function extractValidToken(response) {
var payload = response || {};
var data = payload.data || {};
if (Number(payload.code) !== 200) return '';
if (data.passed === false) return '';
return data.validToken || payload.validToken || '';
}
function getTokenField(form) {
return query('input[name="validToken"]', form);
}
function getCaptchaBox(form) {
// 优先使用页面级弹窗挂载点,避免 TAC 验证码挤占表单布局。
return query('.auth-captcha-modal[data-captcha-box]')
|| query('[data-captcha-box]', form)
|| query('[data-captcha-box]');
}
function writeValidToken(form, token) {
var field = getTokenField(form);
if (field) field.value = token || '';
}
function shouldRequireCaptcha(result) {
// /captcha/require 返回 required=false 时允许直接继续业务请求。
if (!result) return true;
return result.required !== false;
}
function createTac(form, options, api, resolve, reject) {
var settings = options || {};
var box = getCaptchaBox(form);
var context = buildChallengeBody(settings, api);
var lastChallenge = {};
var captcha;
var config;
if (!root.TAC || !root.CaptchaConfig) {
reject(new Error('滑动验证组件未加载'));
return null;
}
if (!box) {
reject(new Error('缺少滑动验证容器'));
return null;
}
config = new root.CaptchaConfig({
bindEl: box,
requestCaptchaDataUrl: api.buildApiUrl('/captcha/challenge'),
validCaptchaUrl: api.buildApiUrl('/captcha/verify'),
requestHeaders: {
clientid: api.clientId
},
validSuccess: function (response, captchaControl, captchaInstance) {
var token = extractValidToken(response);
if (!token) {
reject(new Error('滑动验证未返回有效票据'));
return;
}
writeValidToken(form, token);
if (captchaInstance && captchaInstance.destroyWindow) captchaInstance.destroyWindow();
resolve(token);
},
validFail: function (response, captchaControl, captchaInstance) {
if (captchaInstance && captchaInstance.reloadCaptcha) captchaInstance.reloadCaptcha();
showMessage((response && (response.msg || response.message)) || '滑动验证失败,请重试');
},
btnCloseFun: function (event, captchaInstance) {
if (captchaInstance) captchaInstance.destroyWindow();
reject(new Error('已取消滑动验证'));
}
});
config.addRequestChain({
preRequest: function (type, request) {
if (type === 'requestCaptchaData') {
request.data = buildChallengeBody(settings, api);
}
if (type === 'validCaptcha') {
request.data = buildVerifyBody(request.data, Object.assign({}, context, lastChallenge), api);
}
return true;
},
postRequest: function (type, request, response) {
if (type === 'requestCaptchaData') {
var adapted = adaptChallengeResponse(response);
lastChallenge = {
challengeId: adapted.data && adapted.data.challengeId,
providerCode: adapted.data && adapted.data.providerCode,
captchaType: adapted.data && adapted.data.captchaType
};
Object.keys(response || {}).forEach(function (key) {
delete response[key];
});
Object.assign(response, adapted);
}
if (type === 'validCaptcha') {
Object.assign(response, normalizeVerifyResponse(response));
}
return true;
}
});
captcha = new root.TAC(config, {
bgUrl: 'public/tac/images/dun.jpeg',
logoUrl: null
});
captcha.init();
return captcha;
}
async function ensureToken(form, options) {
// 认证页提交前调用:已有 validToken 直接通过,否则按验证中心策略弹出 TAC。
var api = getApi();
var field = getTokenField(form);
var settings = options || {};
var requirement;
if (!api) return '';
if (field && field.value) return field.value;
if (!settings.sceneCode) return '';
try {
requirement = await api.captchaRequirement(buildChallengeBody(settings, api));
if (!shouldRequireCaptcha(requirement)) return 'CAPTCHA_NOT_REQUIRED';
} catch (error) {
// 查询策略失败时仍尝试直接拉起验证,避免认证接口缺少 validToken。
requirement = null;
}
return new Promise(function (resolve, reject) {
createTac(form, settings, api, resolve, reject);
}).catch(function (error) {
showMessage(error.message || '请先完成滑动验证');
return '';
});
}
return {
buildChallengeBody: buildChallengeBody,
adaptChallengeResponse: adaptChallengeResponse,
buildVerifyBody: buildVerifyBody,
getCaptchaBox: getCaptchaBox,
extractValidToken: extractValidToken,
normalizeVerifyResponse: normalizeVerifyResponse,
shouldRequireCaptcha: shouldRequireCaptcha,
ensureToken: ensureToken
};
});
+384
View File
@@ -0,0 +1,384 @@
(function (root, factory) {
// 祭祀/贺礼/功德模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.CeremonyPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.CeremonyPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
var selectedCeremonyId = '';
function normalizeList(data) {
// 通用列表响应兼容数组、rows、records、list、data。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 标题、姓名和说明进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-ceremony-page], [data-ceremony-edit-page], [data-merit-page], [data-merit-edit-page]');
return getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
getQueryParam(search, 'id') ||
'';
}
function getCurrentCeremonyId() {
var search = root.location && root.location.search;
return getQueryParam(search, 'ceremonyId') || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value, fallback) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : fallback;
}
function buildCeremonyBody(values) {
// CeremonyBody 来自 APP.openapi.jsonceremonyType 和 ceremonyTitle 必填。
var source = values || {};
return {
ceremonyType: String(source.ceremonyType || '').trim(),
ceremonyTitle: String(source.ceremonyTitle || '').trim(),
ceremonyDesc: trimOrUndefined(source.ceremonyDesc),
ceremonyTime: trimOrUndefined(source.ceremonyTime),
location: trimOrUndefined(source.location),
coverOssId: toNumber(source.coverOssId),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function buildGiftBody(values) {
var source = values || {};
return {
giverName: trimOrUndefined(source.giverName),
giftAmount: toNumber(source.giftAmount, 0),
giftMessage: trimOrUndefined(source.giftMessage)
};
}
function buildMeritBody(values) {
// MeritRecordBody 来自 APP.openapi.jsondonorName 和 meritTitle 必填。
var source = values || {};
return {
donorName: String(source.donorName || '').trim(),
meritType: String(source.meritType || '').trim() || 'donation',
meritTitle: String(source.meritTitle || '').trim(),
meritContent: trimOrUndefined(source.meritContent),
amount: toNumber(source.amount, 0),
meritTime: trimOrUndefined(source.meritTime),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function getCeremonyId(item) {
return pick(item, ['ceremonyId', 'id'], '');
}
function buildCeremonyRow(item) {
var ceremonyId = getCeremonyId(item);
var title = pick(item, ['ceremonyTitle', 'title'], '未命名活动');
var type = pick(item, ['ceremonyType', 'type'], 'ceremony');
var time = pick(item, ['ceremonyTime', 'time', 'createTime'], '未设置时间');
var giftCount = pick(item, ['giftCount', 'gifts'], '0');
return '<button class="module-row ceremony-row" type="button" data-ceremony-id="' + escapeHtml(ceremonyId) + '">' +
'<div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(type) + ' · ' + escapeHtml(time) + ' · ' + escapeHtml(giftCount) + ' 条献礼</p></div>' +
'<span class="pill">管理</span></button>';
}
function buildGiftRow(item) {
var name = pick(item, ['giverName', 'memberName', 'name'], '匿名');
var amount = pick(item, ['giftAmount', 'amount'], '0');
var message = pick(item, ['giftMessage', 'message'], '暂无留言');
return '<div class="module-row ceremony-gift-row"><div><h3>' + escapeHtml(name) + '</h3><p>' + escapeHtml(amount) + ' 元 · ' + escapeHtml(message) + '</p></div><span class="pill">献礼</span></div>';
}
function buildMeritRow(item) {
var name = pick(item, ['donorName', 'name'], '未命名功德人');
var title = pick(item, ['meritTitle', 'title'], '功德记录');
var time = pick(item, ['meritTime', 'createTime'], '未记录时间');
return '<div class="module-row merit-row"><div><h3>' + escapeHtml(name) + '</h3><p>' + escapeHtml(title) + ' · ' + escapeHtml(time) + '</p></div><span class="pill">查看</span></div>';
}
function renderCeremonies(items) {
var container = query('[data-ceremony-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无贺礼邀请</div>';
return;
}
container.innerHTML = list.map(buildCeremonyRow).join('');
}
function renderGifts(items) {
var container = query('[data-ceremony-gift-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无献礼记录</div>';
return;
}
container.innerHTML = list.map(buildGiftRow).join('');
}
function renderMerits(items) {
var container = query('[data-merit-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无功德记录</div>';
return;
}
container.innerHTML = list.map(buildMeritRow).join('');
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
async function loadCeremonies() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var ceremonyId = getCurrentCeremonyId();
if (!api || !genealogyId) return;
try {
if (query('[data-ceremony-list]')) {
renderCeremonies(await api.ceremonies(genealogyId));
}
if (ceremonyId && query('[data-ceremony-gift-list]')) {
selectedCeremonyId = ceremonyId;
renderGifts(await api.ceremonyGifts(genealogyId, ceremonyId));
}
} catch (error) {
showMessage(error.message || '贺礼数据加载失败');
}
}
async function loadMerits() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
if (!api || !genealogyId || !query('[data-merit-list]')) return;
try {
renderMerits(await api.meritRecords(genealogyId));
} catch (error) {
showMessage(error.message || '功德记录加载失败');
}
}
async function submitCeremony(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var ceremonyId = getCurrentCeremonyId();
var body = buildCeremonyBody(getFormValues(form));
if (!api || !genealogyId) return;
if (!body.ceremonyType || !body.ceremonyTitle) {
showMessage('请填写贺礼类型和标题');
return;
}
try {
if (ceremonyId) {
await api.updateCeremony(genealogyId, ceremonyId, body);
} else {
await api.createCeremony(genealogyId, body);
}
showMessage('贺礼已保存');
root.location.href = 'profile-gift.html?genealogyId=' + encodeURIComponent(genealogyId);
} catch (error) {
showMessage(error.message || '保存贺礼失败');
}
}
async function submitGift(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var ceremonyId = selectedCeremonyId || getCurrentCeremonyId();
var body = buildGiftBody(getFormValues(form));
if (!api || !genealogyId || !ceremonyId) {
showMessage('请先选择贺礼邀请');
return;
}
try {
await api.createCeremonyGift(genealogyId, ceremonyId, body);
form.reset();
showMessage('献礼已保存');
renderGifts(await api.ceremonyGifts(genealogyId, ceremonyId));
} catch (error) {
showMessage(error.message || '保存献礼失败');
}
}
async function submitMerit(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var body = buildMeritBody(getFormValues(form));
if (!api || !genealogyId) return;
if (!body.donorName || !body.meritTitle) {
showMessage('请填写功德人和功德标题');
return;
}
try {
await api.createMeritRecord(genealogyId, body);
showMessage('功德记录已保存');
root.location.href = 'profile-merit.html?genealogyId=' + encodeURIComponent(genealogyId);
} catch (error) {
showMessage(error.message || '保存功德记录失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('click', function (event) {
var ceremonyButton = event.target.closest('[data-ceremony-id]');
if (!ceremonyButton) return;
selectedCeremonyId = ceremonyButton.getAttribute('data-ceremony-id');
if (getApi() && getCurrentGenealogyId()) {
getApi().ceremonyGifts(getCurrentGenealogyId(), selectedCeremonyId).then(renderGifts).catch(function (error) {
showMessage(error.message || '献礼加载失败');
});
}
});
documentRef.addEventListener('submit', function (event) {
var ceremonyForm = event.target.closest('[data-ceremony-form]');
var giftForm = event.target.closest('[data-ceremony-gift-form]');
var meritForm = event.target.closest('[data-merit-form]');
if (ceremonyForm) {
event.preventDefault();
submitCeremony(ceremonyForm);
}
if (giftForm) {
event.preventDefault();
submitGift(giftForm);
}
if (meritForm) {
event.preventDefault();
submitMerit(meritForm);
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadCeremonies();
loadMerits();
}
return {
normalizeList: normalizeList,
buildCeremonyBody: buildCeremonyBody,
buildMeritBody: buildMeritBody,
buildCeremonyRow: buildCeremonyRow,
init: init
};
});
+321
View File
@@ -0,0 +1,321 @@
(function (root, factory) {
// 家族圈动态模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.FeedPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.FeedPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 动态分页响应兼容 rows、records、list、data。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 动态内容进入 innerHTML 前转义,详情富文本不在这里处理。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-feed-page], [data-feed-edit-page]');
return getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
getQueryParam(search, 'id') ||
'';
}
function getCurrentFeedId() {
var search = root.location && root.location.search;
return getQueryParam(search, 'feedId') || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : undefined;
}
function buildFeedBody(values) {
// FamilyFeedBody 来自 APP.openapi.json。
var source = values || {};
return {
content: String(source.content || '').trim(),
mediaOssIds: trimOrUndefined(source.mediaOssIds),
visibility: String(source.visibility || '').trim() || '2',
status: String(source.status || '').trim() || '0'
};
}
function buildCommentBody(values) {
// FamilyFeedCommentBody 要求 content 必填。
var source = values || {};
return {
parentCommentId: toNumber(source.parentCommentId),
replyUserId: toNumber(source.replyUserId),
content: String(source.content || '').trim()
};
}
function getFeedId(item) {
return pick(item, ['feedId', 'id'], '');
}
function buildFeedRow(item) {
var feedId = getFeedId(item);
var author = pick(item, ['authorName', 'nickName', 'memberName'], '家族成员');
var content = pick(item, ['content', 'feedContent'], '暂无内容');
var likeCount = pick(item, ['likeCount', 'likes'], '0');
var commentCount = pick(item, ['commentCount', 'comments'], '0');
var createTime = pick(item, ['createTime', 'publishTime', 'updateTime'], '未记录时间');
return '<div class="module-row feed-row" data-feed-id="' + escapeHtml(feedId) + '">' +
'<div><h3>' + escapeHtml(author) + '</h3><p>' + escapeHtml(content) + '</p><small>' + escapeHtml(createTime) + ' · ' + escapeHtml(likeCount) + ' 赞 · ' + escapeHtml(commentCount) + ' 评论</small></div>' +
'<div class="row-actions"><button class="pill" type="button" data-feed-like="' + escapeHtml(feedId) + '">点赞</button><button class="pill" type="button" data-feed-comment="' + escapeHtml(feedId) + '">评论</button></div>' +
'</div>';
}
function renderFeeds(items) {
var container = query('[data-feed-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无家族动态</div>';
return;
}
container.innerHTML = list.map(buildFeedRow).join('');
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
if (field.type === 'checkbox') {
values[field.name] = field.checked ? '1' : '';
return;
}
values[field.name] = field.value;
});
return values;
}
function fillFeedForm(feed) {
var source = feed || {};
queryAll('[name]').forEach(function (field) {
var value = pick(source, [field.name], '');
if (field.type === 'checkbox') {
field.checked = value === '1' || value === true;
return;
}
if (value !== '') field.value = value;
});
}
async function loadFeeds() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var feedId = getCurrentFeedId();
if (!api || !genealogyId) return;
try {
if (query('[data-feed-list]')) {
renderFeeds(await api.feedsPage(genealogyId, {
pageNum: 1,
pageSize: 10
}));
}
if (feedId && query('[data-feed-edit-page]')) {
fillFeedForm(await api.feedDetail(genealogyId, feedId));
}
} catch (error) {
showMessage(error.message || '家族动态加载失败');
}
}
async function submitFeed(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var feedId = getCurrentFeedId();
var body = buildFeedBody(getFormValues(form));
if (!api || !genealogyId) {
showMessage('请从具体家谱进入动态发布');
return;
}
if (!body.content) {
showMessage('请填写动态内容');
return;
}
try {
if (feedId) {
await api.updateFeed(genealogyId, feedId, body);
} else {
await api.createFeed(genealogyId, body);
}
showMessage('动态已保存');
root.location.href = 'profile-feed.html?genealogyId=' + encodeURIComponent(genealogyId);
} catch (error) {
showMessage(error.message || '保存动态失败');
}
}
async function likeFeed(feedId) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
if (!api || !genealogyId || !feedId) return;
try {
await api.likeFeed(genealogyId, feedId);
showMessage('已点赞');
loadFeeds();
} catch (error) {
showMessage(error.message || '点赞失败');
}
}
async function commentFeed(feedId) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var content;
if (!api || !genealogyId || !feedId) return;
content = root.prompt('请输入评论内容', '');
if (!content) return;
try {
await api.createFeedComment(genealogyId, feedId, buildCommentBody({
content: content
}));
showMessage('评论已发布');
loadFeeds();
} catch (error) {
showMessage(error.message || '评论失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-feed-form]');
if (!form) return;
event.preventDefault();
submitFeed(form);
});
documentRef.addEventListener('click', function (event) {
var likeButton = event.target.closest('[data-feed-like]');
var commentButton = event.target.closest('[data-feed-comment]');
if (likeButton) {
event.preventDefault();
likeFeed(likeButton.getAttribute('data-feed-like'));
}
if (commentButton) {
event.preventDefault();
commentFeed(commentButton.getAttribute('data-feed-comment'));
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadFeeds();
}
return {
normalizeList: normalizeList,
buildFeedBody: buildFeedBody,
buildCommentBody: buildCommentBody,
buildFeedRow: buildFeedRow,
init: init
};
});
+177
View File
@@ -0,0 +1,177 @@
(function (root, factory) {
// 反馈模块同时支持浏览器页面和 Node 测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.FeedbackPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.FeedbackPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 兼容分页 rows、records、list 和直接数组。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function buildFeedbackBody(values) {
// 接口只接收类型、内容、联系方式;页面上的标题合并到内容前面。
var title = values.feedbackTitle ? '【' + values.feedbackTitle + '】' : '';
return {
feedbackType: values.feedbackType || 'suggestion',
feedbackContent: title + (values.feedbackContent || ''),
contactInfo: values.contactInfo || ''
};
}
function buildFeedbackRow(item) {
var type = pick(item, ['feedbackType', 'typeName'], '反馈');
var content = pick(item, ['feedbackContent', 'content'], '暂无描述');
var status = pick(item, ['status', 'statusName'], '已提交');
var time = pick(item, ['createTime', 'createDate', 'createdAt'], '时间待确认');
return '<div class="module-row"><div><h3>' + type + '</h3><p>' +
status + ' · ' + time + ' · ' + content +
'</p></div><span class="pill">查看</span></div>';
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function readForm(form) {
// name 属性和反馈接口字段保持一致,减少页面文案变化带来的影响。
var values = {};
queryAll('input[name], textarea[name], select[name]', form).forEach(function (field) {
values[field.name] = String(field.value || '').trim();
});
return values;
}
function setBusy(button, busy) {
// 加载态只切换 class,具体样式在 CSS 中维护。
if (!button) return;
button.classList.toggle('is-loading', busy);
if ('disabled' in button) button.disabled = busy;
button.setAttribute('aria-busy', busy ? 'true' : 'false');
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function renderFeedbackList(items) {
var container = query('[data-feedback-list]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无历史反馈</div>';
return;
}
container.innerHTML = items.map(buildFeedbackRow).join('');
}
async function loadFeedbackList() {
var api = getApi();
var container = query('[data-feedback-list]');
if (!api || !container) return;
container.classList.add('is-loading');
try {
renderFeedbackList(normalizeList(await api.feedbackList()));
} catch (error) {
showMessage(error.message || '历史反馈加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function submitFeedback(form, button) {
var api = getApi();
var values = readForm(form);
if (!api) return;
if (!values.feedbackContent) {
showMessage('请填写反馈内容');
return;
}
setBusy(button, true);
try {
await api.submitFeedback(buildFeedbackBody(values));
form.reset();
showMessage('反馈已提交');
loadFeedbackList();
} catch (error) {
showMessage(error.message || '反馈提交失败');
} finally {
setBusy(button, false);
}
}
function bindFeedbackForms() {
queryAll('[data-feedback-form]').forEach(function (form) {
form.addEventListener('submit', function (event) {
event.preventDefault();
submitFeedback(form, query('[type="submit"]', form));
});
});
}
function init() {
if (!documentRef) return;
bindFeedbackForms();
loadFeedbackList();
}
return {
normalizeList: normalizeList,
buildFeedbackBody: buildFeedbackBody,
buildFeedbackRow: buildFeedbackRow,
init: init
};
});
+408
View File
@@ -0,0 +1,408 @@
(function (root, factory) {
// 家谱模块脚本同时支持浏览器运行和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GenealogyPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.GenealogyPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 列表接口可能返回数组、rows、records 或 list,这里统一成数组供页面渲染。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
// 后端字段名存在少量差异时,按优先级取第一个可用字段。
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function buildGenealogyBody(values) {
// 创建家谱接口必填 genealogyName、surname、regionCode,地区编码由地区选择器回填。
var source = values || {};
return {
genealogyName: source.genealogyName || '',
surname: source.surname || '',
regionCode: source.regionCode || '',
addressDetail: source.addressDetail || '',
intro: source.intro || '',
visibility: source.visibility || '1',
joinMode: source.joinMode || '1'
};
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function readForm(form) {
// 页面表单 name 与接口字段对齐,后续加字段只需要补 HTML。
var values = {};
queryAll('input[name], textarea[name], select[name]', form).forEach(function (field) {
values[field.name] = String(field.value || '').trim();
});
return values;
}
function getQueryParam(search, name) {
// 详情页和加入页用 query 参数传递 genealogyId,测试环境也可直接传 search 字符串。
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
return getQueryParam(search, 'id') || getQueryParam(search, 'genealogyId');
}
function escapeHtml(value) {
// 接口内容进入 innerHTML 前统一转义,避免公开页面渲染异常内容。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function setBusy(button, busy) {
// 加载状态只加 class,样式统一写在 CSS 中。
if (!button) return;
button.classList.toggle('is-loading', busy);
if ('disabled' in button) button.disabled = busy;
button.setAttribute('aria-busy', busy ? 'true' : 'false');
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function requireValue(value, message) {
if (value) return true;
showMessage(message);
return false;
}
function buildFamilyHeroTitle(detail) {
return pick(detail, ['genealogyName', 'name', 'title'], '未命名家谱');
}
function formatJoinMode(value) {
// APP.openapi.json 中 joinMode 为枚举值,页面展示时转成中文。
var map = {
0: '关闭加入',
1: '审核加入',
2: '邀请码加入'
};
return map[value] || value || '多人共修';
}
function buildFamilySummary(detail) {
// 后端详情字段可能来自统计字段或普通展示字段,这里集中做字段映射。
var memberCount = pick(detail, ['memberCount', 'membersCount'], '0');
var generationCount = pick(detail, ['generationCount', 'generationTotal'], '0');
var articleCount = pick(detail, ['articleCount', 'articlesCount'], '0');
var albumCount = pick(detail, ['albumCount', 'albumsCount'], '0');
return [
{ label: '成员', value: memberCount },
{ label: '世代', value: generationCount },
{ label: '谱文', value: articleCount },
{ label: '相册', value: albumCount }
];
}
function buildJoinApplyBody(values) {
// 接口文档要求 applicantName、phone、relationDesc、applyReason,可选 inviterUserId。
var source = values || {};
var inviterUserId = source.inviterUserId ? Number(source.inviterUserId) : undefined;
return {
applicantName: String(source.applicantName || '').trim(),
phone: String(source.phone || '').trim(),
relationDesc: String(source.relationDesc || '').trim(),
applyReason: String(source.applyReason || '').trim() || '申请加入家谱',
inviterUserId: inviterUserId
};
}
function renderPublicGenealogies(items) {
// 广场页复用现有卡片结构,只替换接口返回的数据。
var container = query('[data-genealogy-list="public"]');
var html;
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无公开家谱</div>';
return;
}
html = items.slice(0, 6).map(function (item, index) {
// 第一条沿用推荐卡片样式,其余走普通家谱卡片样式。
var id = pick(item, ['genealogyId', 'id'], '');
var name = pick(item, ['genealogyName', 'name', 'title'], '未命名家谱');
var surname = pick(item, ['surname'], '家谱');
var region = pick(item, ['addressDetail', 'regionName', 'originPlace'], '地区待完善');
var intro = pick(item, ['intro', 'description', 'summary'], '家谱资料正在完善中。');
var className = index === 0 ? 'family-card featured tilt-card' : 'card family-lite tilt-card';
return '<a class="' + className + '" href="family-detail.html?id=' + encodeURIComponent(id) + '">' +
'<h3>' + name + '</h3>' +
'<p>' + intro + '</p>' +
'<div class="tag-row"><span class="tag">' + region + '</span><span class="tag">' + surname + '</span></div>' +
'</a>';
}).join('');
container.innerHTML = html;
}
function buildMyGenealogyRow(item) {
// 我的家谱列表保持 profile-module.css 的 module-row 结构。
var id = pick(item, ['genealogyId', 'id'], '');
var name = pick(item, ['genealogyName', 'name'], '未命名家谱');
var role = pick(item, ['roleName', 'memberRole'], '成员');
var count = pick(item, ['memberCount', 'membersCount'], '0');
return '<a class="module-row" href="profile-family-home.html?id=' + encodeURIComponent(id) + '">' +
'<div><h3>' + name + '</h3><p>' + role + ' · 共修入 ' + count + ' 人</p></div>' +
'<span class="pill">进入主页</span></a>';
}
function renderMyGenealogies(items) {
// 没有数据时显示公共空状态,避免保留旧静态示例误导用户。
var container = query('[data-genealogy-list="mine"]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">你还没有创建或加入家谱</div>';
return;
}
container.innerHTML = items.map(buildMyGenealogyRow).join('');
}
function renderFamilyDetail(detail) {
var page = query('[data-family-detail]');
var summaryGrid = query('[data-family-summary]');
var joinLink = query('[data-family-join-link]');
var id;
if (!page) return;
id = pick(detail, ['genealogyId', 'id'], getCurrentGenealogyId());
queryAll('[data-family-text]').forEach(function (node) {
var field = node.getAttribute('data-family-text');
var fallback = node.getAttribute('data-fallback') || '';
var value = field === 'title'
? buildFamilyHeroTitle(detail)
: pick(detail, field.split('|'), fallback);
node.textContent = field.indexOf('joinMode') !== -1 ? formatJoinMode(value) : value;
});
if (summaryGrid) {
summaryGrid.innerHTML = buildFamilySummary(detail).map(function (item) {
return '<span><b>' + escapeHtml(item.value) + '</b>' + escapeHtml(item.label) + '</span>';
}).join('');
}
if (joinLink && id) {
joinLink.href = 'join-genealogy.html?id=' + encodeURIComponent(id);
}
}
async function loadFamilyDetail() {
// 只有详情页存在 data-family-detail,且 URL 带 id/genealogyId 时才请求接口。
var api = getApi();
var page = query('[data-family-detail]');
var genealogyId = getCurrentGenealogyId();
if (!api || !page) return;
if (!genealogyId) {
showMessage('缺少家谱ID');
return;
}
page.classList.add('is-loading');
try {
renderFamilyDetail(await api.genealogyDetail(genealogyId));
} catch (error) {
showMessage(error.message || '家谱详情加载失败');
} finally {
page.classList.remove('is-loading');
}
}
async function submitJoinApply(form, button) {
var api = getApi();
var values = readForm(form);
var genealogyId = values.genealogyId || getCurrentGenealogyId();
var body = buildJoinApplyBody(values);
if (!api) return;
if (!requireValue(genealogyId, '请填写家谱ID或邀请码')) return;
if (!requireValue(body.applicantName, '请填写你的姓名')) return;
if (!requireValue(body.phone, '请填写手机号')) return;
if (!requireValue(body.relationDesc, '请填写关系说明')) return;
setBusy(button, true);
try {
await api.applyJoinGenealogy(genealogyId, body);
showMessage('申请已提交,请等待管理员审核');
root.location.href = form.getAttribute('data-success-url') || 'profile-join-family.html';
} catch (error) {
showMessage(error.message || '申请提交失败');
} finally {
setBusy(button, false);
}
}
async function loadPublicGenealogies() {
// 只有带 data-genealogy-list="public" 的页面才会真正发起请求。
var api = getApi();
var container = query('[data-genealogy-list="public"]');
if (!api || !container) return;
container.classList.add('is-loading');
try {
renderPublicGenealogies(normalizeList(await api.publicGenealogies()));
} catch (error) {
showMessage(error.message || '公开家谱加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function loadMyGenealogies() {
// 只有个人中心“我的家谱”页面会命中这个容器。
var api = getApi();
var container = query('[data-genealogy-list="mine"]');
if (!api || !container) return;
container.classList.add('is-loading');
try {
renderMyGenealogies(normalizeList(await api.myGenealogies()));
} catch (error) {
showMessage(error.message || '我的家谱加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function submitGenealogy(form, button) {
// 创建成功后跳到我的家谱列表,后续继续维护成员和内容。
var api = getApi();
var body = buildGenealogyBody(readForm(form));
if (!api) return;
if (!requireValue(body.genealogyName, '请填写家谱名称')) return;
if (!requireValue(body.surname, '请填写主要姓氏')) return;
if (!requireValue(body.regionCode, '请选择家族所在地')) return;
setBusy(button, true);
try {
await api.createGenealogy(body);
showMessage('家谱创建成功');
root.location.href = form.getAttribute('data-success-url') || 'profile-families.html';
} catch (error) {
showMessage(error.message || '家谱创建失败');
} finally {
setBusy(button, false);
}
}
function bindCreateForm() {
// 创建表单用 submit 事件,兼容按钮点击和键盘回车提交。
var form = query('[data-genealogy-form="create"]');
if (!form) return;
form.addEventListener('submit', function (event) {
event.preventDefault();
submitGenealogy(form, query('[type="submit"]', form));
});
}
function bindJoinForm() {
// 加入页用同一个 submit 入口,兼容详情页带 id 跳转和用户手动输入家谱ID。
var form = query('[data-genealogy-form="join"]');
var idField;
var currentId;
if (!form) return;
idField = query('[name="genealogyId"]', form);
currentId = getCurrentGenealogyId();
if (idField && currentId && !idField.value) idField.value = currentId;
form.addEventListener('submit', function (event) {
event.preventDefault();
submitJoinApply(form, query('[type="submit"]', form));
});
}
function init() {
// 一个模块脚本服务多个家谱页面,通过 data 属性决定当前页面要做什么。
if (!documentRef) return;
bindCreateForm();
bindJoinForm();
loadPublicGenealogies();
loadMyGenealogies();
loadFamilyDetail();
}
return {
normalizeList: normalizeList,
pick: pick,
buildGenealogyBody: buildGenealogyBody,
getQueryParam: getQueryParam,
buildFamilyHeroTitle: buildFamilyHeroTitle,
buildFamilySummary: buildFamilySummary,
formatJoinMode: formatJoinMode,
buildJoinApplyBody: buildJoinApplyBody,
buildMyGenealogyRow: buildMyGenealogyRow,
init: init
};
});
+349
View File
@@ -0,0 +1,349 @@
(function (root, factory) {
// 字辈谱模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GenerationPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.GenerationPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 通用列表响应可能是数组,也可能包在 rows、records、list 或 data 中。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 字辈文本进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
if (!documentRef) return null;
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
if (!documentRef) return [];
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
if (root.alert) {
root.alert(message);
}
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-generation-page]');
return getQueryParam(search, 'id') ||
getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
'';
}
function toNumber(value, fallback) {
var number = Number(String(value || '').trim());
return Number.isFinite(number) && number > 0 ? number : fallback;
}
function toBoolean(value) {
return value === true || value === 'true' || value === '1' || value === 'on';
}
function buildGenerationBody(values) {
// GenerationPoemBody 必填 generationNo、generationText,其余字段给接口默认值。
var source = values || {};
var generationNo = toNumber(source.generationNo, 1);
return {
generationNo: generationNo,
generationText: String(source.generationText || '').trim(),
description: String(source.description || '').trim(),
sortOrder: toNumber(source.sortOrder, generationNo),
status: String(source.status || '').trim() || '0'
};
}
function buildGenerationBatchBody(values) {
// GenerationPoemBatchBody 只包含批量文本和是否遇到断代即停止。
var source = values || {};
return {
content: String(source.content || '').trim(),
stopMissingOldGeneration: toBoolean(source.stopMissingOldGeneration)
};
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
if (field.type === 'checkbox') {
values[field.name] = field.checked ? 'on' : '';
return;
}
values[field.name] = field.value;
});
return values;
}
function setBatchStatus(message) {
var statusNode = query('[data-generation-batch-status]');
if (statusNode) {
statusNode.textContent = message || '';
}
}
function buildGenerationRow(item, genealogyId) {
var poemId = pick(item, ['poemId', 'id'], '');
var generationNo = pick(item, ['generationNo', 'generation', 'sortOrder'], '1');
var text = pick(item, ['generationText', 'content', 'text'], '未设置');
var memberCount = pick(item, ['memberCount', 'personCount', 'count'], '0');
var description = pick(item, ['description', 'remark'], '暂无备注');
return '<div class="module-row generation-row" data-generation-id="' + escapeHtml(poemId) + '">' +
'<div><h3>第 ' + escapeHtml(generationNo) + ' 代:' + escapeHtml(text) + '</h3><p>' + escapeHtml(memberCount) + ' 人 · ' + escapeHtml(description) + '</p></div>' +
'<button class="pill" type="button" data-generation-edit="' + escapeHtml(poemId) + '" data-generation-no="' + escapeHtml(generationNo) + '" data-generation-text="' + escapeHtml(text) + '" data-genealogy-id="' + escapeHtml(genealogyId) + '">编辑</button>' +
'</div>';
}
function renderGenerations(items, genealogyId) {
var container = query('[data-generation-list]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无字辈记录</div>';
return;
}
container.innerHTML = items.map(function (item) {
return buildGenerationRow(item, genealogyId);
}).join('');
}
function renderBatchPreview(data) {
var container = query('[data-generation-batch-preview]');
var items = normalizeList(data);
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">预览完成,接口未返回明细</div>';
return;
}
container.innerHTML = items.map(function (item) {
return buildGenerationRow(item, getCurrentGenealogyId());
}).join('');
}
async function loadGenerations() {
var api = getApi();
var container = query('[data-generation-list]');
var genealogyId = getCurrentGenealogyId();
if (!api || !container) return;
if (!genealogyId) {
container.innerHTML = '<div class="api-empty">请从具体家谱进入字辈谱</div>';
return;
}
container.classList.add('is-loading');
try {
renderGenerations(normalizeList(await api.generationPoems(genealogyId)), genealogyId);
} catch (error) {
showMessage(error.message || '字辈谱加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function createGeneration() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var generationNo;
var generationText;
var body;
if (!api || !genealogyId) {
showMessage('请从具体家谱进入字辈谱');
return;
}
generationNo = root.prompt('请输入世代序号', '');
if (!generationNo) return;
generationText = root.prompt('请输入字辈内容', '');
if (!generationText) return;
body = buildGenerationBody({
generationNo: generationNo,
generationText: generationText
});
try {
await api.createGenerationPoem(genealogyId, body);
showMessage('字辈已新增');
loadGenerations();
} catch (error) {
showMessage(error.message || '新增字辈失败');
}
}
async function editGeneration(button) {
var api = getApi();
var genealogyId = button.getAttribute('data-genealogy-id') || getCurrentGenealogyId();
var poemId = button.getAttribute('data-generation-edit');
var currentText = button.getAttribute('data-generation-text') || '';
var generationNo = button.getAttribute('data-generation-no') || '1';
var nextText;
if (!api || !genealogyId || !poemId) return;
nextText = root.prompt('请输入新的字辈', currentText);
if (!nextText) return;
button.classList.add('is-loading');
try {
await api.updateGenerationPoem(genealogyId, poemId, buildGenerationBody({
generationNo: generationNo,
generationText: nextText
}));
showMessage('字辈已更新');
loadGenerations();
} catch (error) {
showMessage(error.message || '更新字辈失败');
} finally {
button.classList.remove('is-loading');
}
}
async function submitGenerationBatch(action) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var form = query('[data-generation-batch-form]');
var body;
var result;
if (!api || !genealogyId || !form) {
showMessage('请从具体家谱进入字辈谱');
return;
}
body = buildGenerationBatchBody(getFormValues(form));
if (!body.content) {
showMessage('请填写批量字辈内容');
return;
}
try {
setBatchStatus(action === 'save' ? '批量保存中...' : '批量预览中...');
if (action === 'save') {
await api.saveGenerationPoemsBatch(genealogyId, body);
setBatchStatus('批量保存完成');
showMessage('批量字辈已保存');
loadGenerations();
return;
}
result = await api.previewGenerationPoems(genealogyId, body);
renderBatchPreview(result);
setBatchStatus('批量预览完成');
} catch (error) {
setBatchStatus('批量处理失败');
showMessage(error.message || '批量字辈处理失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('click', function (event) {
var addButton = event.target.closest('[data-generation-add]');
var editButton = event.target.closest('[data-generation-edit]');
var batchButton = event.target.closest('[data-generation-batch-action]');
if (addButton) {
event.preventDefault();
createGeneration();
}
if (editButton) {
event.preventDefault();
editGeneration(editButton);
}
if (batchButton) {
event.preventDefault();
submitGenerationBatch(batchButton.getAttribute('data-generation-batch-action'));
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadGenerations();
}
return {
normalizeList: normalizeList,
buildGenerationBody: buildGenerationBody,
buildGenerationBatchBody: buildGenerationBatchBody,
buildGenerationRow: buildGenerationRow,
init: init
};
});
+245
View File
@@ -0,0 +1,245 @@
(function (root, factory) {
// 成长记录模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.GrowthPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.GrowthPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 成长记录列表兼容数组、rows、records、list、data。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 成长记录标题和内容进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-growth-page], [data-growth-edit-page]');
return getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
getQueryParam(search, 'id') ||
'';
}
function getCurrentRecordId() {
var search = root.location && root.location.search;
return getQueryParam(search, 'recordId') || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value, fallback) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : fallback;
}
function buildGrowthBody(values) {
// GrowthRecordBody 来自 APP.openapi.jsonrecordTitle 必填。
var source = values || {};
return {
lineagePersonId: toNumber(source.lineagePersonId),
recordType: String(source.recordType || '').trim() || 'growth',
recordTitle: String(source.recordTitle || '').trim(),
recordContent: trimOrUndefined(source.recordContent),
recordDate: trimOrUndefined(source.recordDate),
remindTime: trimOrUndefined(source.remindTime),
mediaOssIds: trimOrUndefined(source.mediaOssIds),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function getRecordId(item) {
return pick(item, ['recordId', 'id'], '');
}
function buildGrowthRow(item, genealogyId) {
var recordId = getRecordId(item);
var title = pick(item, ['recordTitle', 'title'], '未命名成长记录');
var type = pick(item, ['recordType', 'type'], 'growth');
var date = pick(item, ['recordDate', 'createTime'], '未记录日期');
return '<a class="module-row growth-row" href="profile-growth-edit.html?recordId=' + encodeURIComponent(recordId) + '&genealogyId=' + encodeURIComponent(genealogyId || '') + '">' +
'<div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(type) + ' · ' + escapeHtml(date) + '</p></div>' +
'<span class="pill">编辑</span></a>';
}
function renderGrowthRecords(items, genealogyId) {
var container = query('[data-growth-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无成长记录</div>';
return;
}
container.innerHTML = list.map(function (item) {
return buildGrowthRow(item, genealogyId);
}).join('');
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
function fillGrowthForm(record) {
var source = record || {};
queryAll('[name]').forEach(function (field) {
var value = pick(source, [field.name], '');
if (value !== '') field.value = value;
});
}
async function loadGrowthRecords() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var recordId = getCurrentRecordId();
if (!api || !genealogyId) return;
try {
if (query('[data-growth-list]')) {
renderGrowthRecords(await api.growthRecords(genealogyId), genealogyId);
}
if (recordId && query('[data-growth-edit-page]')) {
fillGrowthForm(await api.growthRecordDetail(genealogyId, recordId));
}
} catch (error) {
showMessage(error.message || '成长记录加载失败');
}
}
async function submitGrowth(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var recordId = getCurrentRecordId();
var body = buildGrowthBody(getFormValues(form));
if (!api || !genealogyId) return;
if (!body.recordTitle) {
showMessage('请填写成长记录标题');
return;
}
try {
if (recordId) {
await api.updateGrowthRecord(genealogyId, recordId, body);
} else {
await api.createGrowthRecord(genealogyId, body);
}
showMessage('成长记录已保存');
root.location.href = 'profile-growth.html?genealogyId=' + encodeURIComponent(genealogyId);
} catch (error) {
showMessage(error.message || '保存成长记录失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-growth-form]');
if (!form) return;
event.preventDefault();
submitGrowth(form);
});
}
function init() {
if (!documentRef) return;
bindActions();
loadGrowthRecords();
}
return {
normalizeList: normalizeList,
buildGrowthBody: buildGrowthBody,
buildGrowthRow: buildGrowthRow,
init: init
};
});
+156
View File
@@ -0,0 +1,156 @@
(function (root, factory) {
// 帮助中心模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.HelpPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.HelpPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 通用列表响应可能是数组,也可能包在 rows、records、list 或 data 中。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 帮助文章来自接口,进入 innerHTML 前先转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function buildHelpItem(item, index) {
// 列表接口字段未在文档中细化,这里兼容常见标题和摘要字段。
var id = pick(item, ['helpId', 'id', 'articleId'], '');
var title = pick(item, ['title', 'articleTitle', 'name'], '帮助文章');
var content = pick(item, ['summary', 'description', 'content', 'articleContent'], '暂无详细说明');
var hasFullContent = Boolean(pick(item, ['content', 'articleContent'], ''));
var open = index === 0 ? ' open' : '';
return '<details' + open + ' class="tilt-card" data-help-id="' + escapeHtml(id) + '" data-help-loaded="' + (hasFullContent ? 'true' : 'false') + '">' +
'<summary>' + escapeHtml(title) + '</summary>' +
'<p>' + escapeHtml(content) + '</p>' +
'</details>';
}
function renderHelpArticles(items) {
var container = query('[data-help-list]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无帮助文章</div>';
return;
}
container.innerHTML = items.map(buildHelpItem).join('');
}
async function loadHelpArticles() {
var api = getApi();
var container = query('[data-help-list]');
if (!api || !container) return;
container.classList.add('is-loading');
try {
renderHelpArticles(normalizeList(await api.helpArticles()));
} catch (error) {
showMessage(error.message || '帮助文章加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function loadHelpDetail(details) {
var api = getApi();
var helpId = details && details.getAttribute('data-help-id');
var paragraph = details && query('p', details);
var content;
if (!api || !details || !helpId || details.getAttribute('data-help-loaded') === 'true') return;
details.classList.add('is-loading');
try {
content = await api.helpArticleDetail(helpId);
paragraph.textContent = pick(content, ['content', 'articleContent', 'summary', 'description'], paragraph.textContent);
details.setAttribute('data-help-loaded', 'true');
} catch (error) {
showMessage(error.message || '帮助详情加载失败');
} finally {
details.classList.remove('is-loading');
}
}
function bindDetailLoad() {
var container = query('[data-help-list]');
if (!container) return;
container.addEventListener('toggle', function (event) {
if (event.target && event.target.matches('details') && event.target.open) {
loadHelpDetail(event.target);
}
}, true);
}
function init() {
if (!documentRef) return;
bindDetailLoad();
loadHelpArticles();
}
return {
normalizeList: normalizeList,
buildHelpItem: buildHelpItem,
renderHelpArticles: renderHelpArticles,
init: init
};
});
+271
View File
@@ -0,0 +1,271 @@
(function (root, factory) {
// 加入申请模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.JoinApplyPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.JoinApplyPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 列表响应可能直接是数组,也可能使用 rows、records、list 或 data 包裹。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 申请人信息来自接口,渲染前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var fromQuery = getQueryParam(search, 'id') || getQueryParam(search, 'genealogyId');
var fromPage = query('[data-genealogy-id]');
return fromQuery || (fromPage && fromPage.getAttribute('data-genealogy-id')) || '';
}
function formatApplyStatus(status) {
// 审核接口要求 status,按常见字典值做页面中文展示。
var map = {
0: '待审核',
1: '已通过',
2: '已拒绝'
};
return map[status] || status || '待审核';
}
function buildAuditBody(action, remark) {
var isReject = action === 'reject';
return {
status: isReject ? '2' : '1',
auditRemark: remark || (isReject ? '信息核验未通过' : '信息核验通过')
};
}
function buildPendingRow(item, genealogyId) {
var applyId = pick(item, ['applyId', 'id'], '');
var name = pick(item, ['applicantName', 'name', 'nickName'], '未命名申请人');
var relation = pick(item, ['relationDesc', 'applyReason', 'remark'], '关系说明待确认');
var time = pick(item, ['createTime', 'createdAt', 'applyTime'], '提交时间待确认');
return '<div class="module-row join-apply-row" data-join-apply-id="' + escapeHtml(applyId) + '">' +
'<div><h3>' + escapeHtml(name) + '申请加入家谱</h3><p>' + escapeHtml(time) + ' · ' + escapeHtml(relation) + '</p></div>' +
'<div class="bottom-actions">' +
'<button class="btn primary" type="button" data-join-audit="approve" data-genealogy-id="' + escapeHtml(genealogyId) + '" data-apply-id="' + escapeHtml(applyId) + '">同意</button>' +
'<button class="btn ghost" type="button" data-join-audit="reject" data-genealogy-id="' + escapeHtml(genealogyId) + '" data-apply-id="' + escapeHtml(applyId) + '">拒绝</button>' +
'</div></div>';
}
function buildMineRow(item) {
var applyId = pick(item, ['applyId', 'id'], '');
var genealogyName = pick(item, ['genealogyName', 'familyName', 'name'], '未命名家谱');
var status = formatApplyStatus(pick(item, ['status', 'auditStatus'], '0'));
var relation = pick(item, ['relationDesc', 'applyReason', 'auditRemark'], '关系说明待确认');
var action = status === '待审核'
? '<button class="btn ghost" type="button" data-join-cancel="' + escapeHtml(applyId) + '">撤销申请</button>'
: '<span class="pill">' + escapeHtml(status) + '</span>';
return '<div class="module-row join-apply-row" data-join-apply-id="' + escapeHtml(applyId) + '">' +
'<div><h3>' + escapeHtml(genealogyName) + '</h3><p>' + escapeHtml(status) + ' · ' + escapeHtml(relation) + '</p></div>' +
action +
'</div>';
}
function renderPending(items, genealogyId) {
var container = query('[data-join-apply-list="pending"]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无待审核申请</div>';
return;
}
container.innerHTML = items.map(function (item) {
return buildPendingRow(item, genealogyId);
}).join('');
}
function renderMine(items) {
var container = query('[data-join-apply-list="mine"]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无加入申请记录</div>';
return;
}
container.innerHTML = items.map(buildMineRow).join('');
}
async function loadPending() {
var api = getApi();
var container = query('[data-join-apply-list="pending"]');
var genealogyId = getCurrentGenealogyId();
if (!api || !container) return;
if (!genealogyId) {
container.innerHTML = '<div class="api-empty">请从具体家谱进入审核页</div>';
return;
}
container.classList.add('is-loading');
try {
renderPending(normalizeList(await api.pendingJoinApplies(genealogyId)), genealogyId);
} catch (error) {
showMessage(error.message || '待审核申请加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function loadMine() {
var api = getApi();
var container = query('[data-join-apply-list="mine"]');
if (!api || !container) return;
container.classList.add('is-loading');
try {
renderMine(normalizeList(await api.myJoinApplies()));
} catch (error) {
showMessage(error.message || '加入申请记录加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function audit(button) {
var api = getApi();
var action = button.getAttribute('data-join-audit');
var genealogyId = button.getAttribute('data-genealogy-id');
var applyId = button.getAttribute('data-apply-id');
var remark = action === 'reject' ? root.prompt('请输入拒绝原因', '') : '';
if (!api || !genealogyId || !applyId) return;
if (action === 'reject' && remark === null) return;
button.classList.add('is-loading');
try {
await api.auditJoinApply(genealogyId, applyId, buildAuditBody(action, remark));
showMessage(action === 'reject' ? '已拒绝申请' : '已同意申请');
loadPending();
} catch (error) {
showMessage(error.message || '审核申请失败');
} finally {
button.classList.remove('is-loading');
}
}
async function cancel(button) {
var api = getApi();
var applyId = button.getAttribute('data-join-cancel');
if (!api || !applyId) return;
if (root.confirm && !root.confirm('确认撤销当前加入申请?')) return;
button.classList.add('is-loading');
try {
await api.cancelJoinApply(applyId);
showMessage('已撤销加入申请');
loadMine();
} catch (error) {
showMessage(error.message || '撤销申请失败');
} finally {
button.classList.remove('is-loading');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('click', function (event) {
var auditButton = event.target.closest('[data-join-audit]');
var cancelButton = event.target.closest('[data-join-cancel]');
if (auditButton) {
event.preventDefault();
audit(auditButton);
}
if (cancelButton) {
event.preventDefault();
cancel(cancelButton);
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadPending();
loadMine();
}
return {
normalizeList: normalizeList,
formatApplyStatus: formatApplyStatus,
buildAuditBody: buildAuditBody,
buildPendingRow: buildPendingRow,
buildMineRow: buildMineRow,
init: init
};
});
+2
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+948
View File
@@ -0,0 +1,948 @@
/* common */
.ke-inline-block {
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
}
.ke-clearfix {
zoom: 1;
}
.ke-clearfix:after {
content: ".";
display: block;
clear: both;
font-size: 0;
height: 0;
line-height: 0;
visibility: hidden;
}
.ke-shadow {
box-shadow: 1px 1px 3px #A0A0A0;
-moz-box-shadow: 1px 1px 3px #A0A0A0;
-webkit-box-shadow: 1px 1px 3px #A0A0A0;
filter: progid:DXImageTransform.Microsoft.Shadow(color='#A0A0A0', Direction=135, Strength=3);
background-color: #F0F0EE;
}
.ke-menu a,
.ke-menu a:hover,
.ke-dialog a,
.ke-dialog a:hover {
color: #337FE5;
text-decoration: none;
}
/* icons */
.ke-icon-source {
background-position: 0px 0px;
width: 16px;
height: 16px;
}
.ke-icon-preview {
background-position: 0px -16px;
width: 16px;
height: 16px;
}
.ke-icon-print {
background-position: 0px -32px;
width: 16px;
height: 16px;
}
.ke-icon-undo {
background-position: 0px -48px;
width: 16px;
height: 16px;
}
.ke-icon-redo {
background-position: 0px -64px;
width: 16px;
height: 16px;
}
.ke-icon-cut {
background-position: 0px -80px;
width: 16px;
height: 16px;
}
.ke-icon-copy {
background-position: 0px -96px;
width: 16px;
height: 16px;
}
.ke-icon-paste {
background-position: 0px -112px;
width: 16px;
height: 16px;
}
.ke-icon-selectall {
background-position: 0px -128px;
width: 16px;
height: 16px;
}
.ke-icon-justifyleft {
background-position: 0px -144px;
width: 16px;
height: 16px;
}
.ke-icon-justifycenter {
background-position: 0px -160px;
width: 16px;
height: 16px;
}
.ke-icon-justifyright {
background-position: 0px -176px;
width: 16px;
height: 16px;
}
.ke-icon-justifyfull {
background-position: 0px -192px;
width: 16px;
height: 16px;
}
.ke-icon-insertorderedlist {
background-position: 0px -208px;
width: 16px;
height: 16px;
}
.ke-icon-insertunorderedlist {
background-position: 0px -224px;
width: 16px;
height: 16px;
}
.ke-icon-indent {
background-position: 0px -240px;
width: 16px;
height: 16px;
}
.ke-icon-outdent {
background-position: 0px -256px;
width: 16px;
height: 16px;
}
.ke-icon-subscript {
background-position: 0px -272px;
width: 16px;
height: 16px;
}
.ke-icon-superscript {
background-position: 0px -288px;
width: 16px;
height: 16px;
}
.ke-icon-date {
background-position: 0px -304px;
width: 25px;
height: 16px;
}
.ke-icon-time {
background-position: 0px -320px;
width: 25px;
height: 16px;
}
.ke-icon-formatblock {
background-position: 0px -336px;
width: 25px;
height: 16px;
}
.ke-icon-fontname {
background-position: 0px -352px;
width: 21px;
height: 16px;
}
.ke-icon-fontsize {
background-position: 0px -368px;
width: 23px;
height: 16px;
}
.ke-icon-forecolor {
background-position: 0px -384px;
width: 20px;
height: 16px;
}
.ke-icon-hilitecolor {
background-position: 0px -400px;
width: 23px;
height: 16px;
}
.ke-icon-bold {
background-position: 0px -416px;
width: 16px;
height: 16px;
}
.ke-icon-italic {
background-position: 0px -432px;
width: 16px;
height: 16px;
}
.ke-icon-underline {
background-position: 0px -448px;
width: 16px;
height: 16px;
}
.ke-icon-strikethrough {
background-position: 0px -464px;
width: 16px;
height: 16px;
}
.ke-icon-removeformat {
background-position: 0px -480px;
width: 16px;
height: 16px;
}
.ke-icon-image {
background-position: 0px -496px;
width: 16px;
height: 16px;
}
.ke-icon-flash {
background-position: 0px -512px;
width: 16px;
height: 16px;
}
.ke-icon-media {
background-position: 0px -528px;
width: 16px;
height: 16px;
}
.ke-icon-div {
background-position: 0px -544px;
width: 16px;
height: 16px;
}
.ke-icon-formula {
background-position: 0px -576px;
width: 16px;
height: 16px;
}
.ke-icon-hr {
background-position: 0px -592px;
width: 16px;
height: 16px;
}
.ke-icon-emoticons {
background-position: 0px -608px;
width: 16px;
height: 16px;
}
.ke-icon-link {
background-position: 0px -624px;
width: 16px;
height: 16px;
}
.ke-icon-unlink {
background-position: 0px -640px;
width: 16px;
height: 16px;
}
.ke-icon-fullscreen {
background-position: 0px -656px;
width: 16px;
height: 16px;
}
.ke-icon-about {
background-position: 0px -672px;
width: 16px;
height: 16px;
}
.ke-icon-plainpaste {
background-position: 0px -704px;
width: 16px;
height: 16px;
}
.ke-icon-wordpaste {
background-position: 0px -720px;
width: 16px;
height: 16px;
}
.ke-icon-table {
background-position: 0px -784px;
width: 16px;
height: 16px;
}
.ke-icon-tablemenu {
background-position: 0px -768px;
width: 16px;
height: 16px;
}
.ke-icon-tableinsert {
background-position: 0px -784px;
width: 16px;
height: 16px;
}
.ke-icon-tabledelete {
background-position: 0px -800px;
width: 16px;
height: 16px;
}
.ke-icon-tablecolinsertleft {
background-position: 0px -816px;
width: 16px;
height: 16px;
}
.ke-icon-tablecolinsertright {
background-position: 0px -832px;
width: 16px;
height: 16px;
}
.ke-icon-tablerowinsertabove {
background-position: 0px -848px;
width: 16px;
height: 16px;
}
.ke-icon-tablerowinsertbelow {
background-position: 0px -864px;
width: 16px;
height: 16px;
}
.ke-icon-tablecoldelete {
background-position: 0px -880px;
width: 16px;
height: 16px;
}
.ke-icon-tablerowdelete {
background-position: 0px -896px;
width: 16px;
height: 16px;
}
.ke-icon-tablecellprop {
background-position: 0px -912px;
width: 16px;
height: 16px;
}
.ke-icon-tableprop {
background-position: 0px -928px;
width: 16px;
height: 16px;
}
.ke-icon-checked {
background-position: 0px -944px;
width: 16px;
height: 16px;
}
.ke-icon-code {
background-position: 0px -960px;
width: 16px;
height: 16px;
}
.ke-icon-map {
background-position: 0px -976px;
width: 16px;
height: 16px;
}
.ke-icon-baidumap {
background-position: 0px -976px;
width: 16px;
height: 16px;
}
.ke-icon-lineheight {
background-position: 0px -992px;
width: 16px;
height: 16px;
}
.ke-icon-clearhtml {
background-position: 0px -1008px;
width: 16px;
height: 16px;
}
.ke-icon-pagebreak {
background-position: 0px -1024px;
width: 16px;
height: 16px;
}
.ke-icon-insertfile {
background-position: 0px -1040px;
width: 16px;
height: 16px;
}
.ke-icon-quickformat {
background-position: 0px -1056px;
width: 16px;
height: 16px;
}
.ke-icon-template {
background-position: 0px -1072px;
width: 16px;
height: 16px;
}
.ke-icon-tablecellsplit {
background-position: 0px -1088px;
width: 16px;
height: 16px;
}
.ke-icon-tablerowmerge {
background-position: 0px -1104px;
width: 16px;
height: 16px;
}
.ke-icon-tablerowsplit {
background-position: 0px -1120px;
width: 16px;
height: 16px;
}
.ke-icon-tablecolmerge {
background-position: 0px -1136px;
width: 16px;
height: 16px;
}
.ke-icon-tablecolsplit {
background-position: 0px -1152px;
width: 16px;
height: 16px;
}
.ke-icon-anchor {
background-position: 0px -1168px;
width: 16px;
height: 16px;
}
.ke-icon-search {
background-position: 0px -1184px;
width: 16px;
height: 16px;
}
.ke-icon-new {
background-position: 0px -1200px;
width: 16px;
height: 16px;
}
.ke-icon-specialchar {
background-position: 0px -1216px;
width: 16px;
height: 16px;
}
.ke-icon-multiimage {
background-position: 0px -1232px;
width: 16px;
height: 16px;
}
.ke-icon-zijianju {
background-position: 0px -1248px;
width: 16px;
height: 16px;
}
.ke-icon-duansuo {
background-position: 0px -1264px;
width: 16px;
height: 16px;
}
/* container */
.ke-container {
display: block;
/*border: 1px solid #CCCCCC;*/
background-color: #FFF;
overflow: hidden;
padding: 0;
}
/* toolbar */
.ke-toolbar {
border-bottom: 1px solid #CCC;
background-color: #F0F0EE;
text-align: left;
overflow: hidden;
zoom: 1;
}
.ke-toolbar-icon {
background-repeat: no-repeat;
font-size: 0;
line-height: 0;
overflow: hidden;
display: block;
}
.ke-toolbar-icon-url {
background-image: url(default.png);
}
.ke-toolbar .ke-outline {
border: 1px solid #F0F0EE;
/*margin: 1px;*/
margin: 8px 9px;
padding: 1px 2px;
font-size: 0;
line-height: 0;
overflow: hidden;
cursor: pointer;
display: block;
float: left;
}
.ke-toolbar .ke-on {
border: 1px solid #5690D2;
}
.ke-toolbar .ke-selected {
border: 1px solid #5690D2;
background-color: #E9EFF6;
}
.ke-toolbar .ke-disabled {
cursor: default;
}
.ke-toolbar .ke-separator {
height: 16px;
margin: 2px 3px;
border-left: 1px solid #A0A0A0;
border-right: 1px solid #FFFFFF;
border-top:0;
border-bottom:0;
width: 0;
font-size: 0;
line-height: 0;
overflow: hidden;
display: block;
float: left;
}
.ke-toolbar .ke-hr {
overflow: hidden;
height: 1px;
clear: both;
}
/* edit */
.ke-edit {
padding: 0;
}
.ke-edit-iframe,
.ke-edit-textarea {
border: 0;
margin: 0;
padding: 0;
overflow: auto;
}
.ke-edit-textarea {
font: 12px/1.5 "Consolas", "Monaco", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
color: #000;
overflow: auto;
resize: none;
}
.ke-edit-textarea:focus {
outline: none;
}
/* statusbar */
.ke-statusbar {
position: relative;
background-color: #F0F0EE;
border-top: 1px solid #CCCCCC;
font-size: 0;
line-height: 0;
*height: 12px;
overflow: hidden;
text-align: center;
cursor: s-resize;
}
.ke-statusbar-center-icon {
background-position: -0px -754px;
width: 15px;
height: 11px;
background-image: url(default.png);
}
.ke-statusbar-right-icon {
position: absolute;
right: 0;
bottom: 0;
cursor: se-resize;
background-position: -5px -741px;
width: 11px;
height: 11px;
background-image: url(default.png);
}
/* menu */
.ke-menu {
border: 1px solid #A0A0A0;
background-color: #F1F1F1;
color: #222222;
padding: 2px;
font-family: "sans serif",tahoma,verdana,helvetica;
font-size: 12px;
text-align: left;
overflow: hidden;
}
.ke-menu-item {
border: 1px solid #F1F1F1;
background-color: #F1F1F1;
color: #222222;
height: 24px;
overflow: hidden;
cursor: pointer;
}
.ke-menu-item-on {
border: 1px solid #5690D2;
background-color: #E9EFF6;
}
.ke-menu-item-left {
width: 27px;
text-align: center;
overflow: hidden;
}
.ke-menu-item-center {
width: 0;
height: 24px;
border-left: 1px solid #E3E3E3;
border-right: 1px solid #FFFFFF;
border-top: 0;
border-bottom: 0;
}
.ke-menu-item-center-on {
border-left: 1px solid #E9EFF6;
border-right: 1px solid #E9EFF6;
}
.ke-menu-item-right {
border: 0;
padding: 0 0 0 5px;
line-height: 24px;
text-align: left;
overflow: hidden;
}
.ke-menu-separator {
margin: 2px 0;
height: 0;
overflow: hidden;
border-top: 1px solid #CCCCCC;
border-bottom: 1px solid #FFFFFF;
border-left: 0;
border-right: 0;
}
/* colorpicker */
.ke-colorpicker {
border: 1px solid #A0A0A0;
background-color: #F1F1F1;
color: #222222;
padding: 2px;
}
.ke-colorpicker-table {
border:0;
margin:0;
padding:0;
border-collapse: separate;
}
.ke-colorpicker-cell {
font-size: 0;
line-height: 0;
border: 1px solid #F0F0EE;
cursor: pointer;
margin:3px;
padding:0;
}
.ke-colorpicker-cell-top {
font-family: "sans serif",tahoma,verdana,helvetica;
font-size: 12px;
line-height: 24px;
border: 1px solid #F0F0EE;
cursor: pointer;
margin:0;
padding:0;
text-align: center;
}
.ke-colorpicker-cell-on {
border: 1px solid #5690D2;
}
.ke-colorpicker-cell-selected {
border: 1px solid #2446AB;
}
.ke-colorpicker-cell-color {
width: 14px;
height: 14px;
margin: 3px;
padding: 0;
border: 0;
}
/* dialog */
.ke-dialog {
position: absolute;
margin: 0;
padding: 0;
}
.ke-dialog .ke-header {
width: 100%;
margin-bottom: 10px;
}
.ke-dialog .ke-header .ke-left {
float: left;
}
.ke-dialog .ke-header .ke-right {
float: right;
}
.ke-dialog .ke-header label {
margin-right: 0;
cursor: pointer;
font-weight: normal;
display: inline;
vertical-align: top;
}
.ke-dialog-content {
background-color: #FFF;
width: 100%;
height: 100%;
color: #333;
border: 1px solid #A0A0A0;
}
.ke-dialog-shadow {
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: 3px 3px 7px #999;
-moz-box-shadow: 3px 3px 7px #999;
-webkit-box-shadow: 3px 3px 7px #999;
filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius='3', MakeShadow='true', ShadowOpacity='0.4');
background-color: #F0F0EE;
}
.ke-dialog-header {
border:0;
margin:0;
padding: 0 10px;
background: url(background.png) repeat scroll 0 0 #F0F0EE;
border-bottom: 1px solid #CFCFCF;
height: 24px;
font: 12px/24px "sans serif",tahoma,verdana,helvetica;
text-align: left;
color: #222;
cursor: move;
}
.ke-dialog-icon-close {
display: block;
background: url(default.png) no-repeat scroll 0px -688px;
width: 16px;
height: 16px;
position: absolute;
right: 6px;
top: 6px;
cursor: pointer;
}
.ke-dialog-body {
font: 12px/1.5 "sans serif",tahoma,verdana,helvetica;
text-align: left;
overflow: hidden;
width: 100%;
}
.ke-dialog-body textarea {
display: block;
overflow: auto;
padding: 0;
resize: none;
}
.ke-dialog-body textarea:focus,
.ke-dialog-body input:focus,
.ke-dialog-body select:focus {
outline: none;
}
.ke-dialog-body label {
margin-right: 10px;
cursor: pointer;
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
}
.ke-dialog-body img {
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
}
.ke-dialog-body select {
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
width: auto;
}
.ke-dialog-body .ke-textarea {
display: block;
width: 408px;
height: 260px;
font-family: "sans serif",tahoma,verdana,helvetica;
font-size: 12px;
border-color: #848484 #E0E0E0 #E0E0E0 #848484;
border-style: solid;
border-width: 1px;
}
.ke-dialog-body .ke-form {
margin: 0;
padding: 0;
}
.ke-dialog-loading {
position: absolute;
top: 0;
left: 1px;
z-index: 1;
text-align: center;
}
.ke-dialog-loading-content {
background: url("../common/loading.gif") no-repeat;
color: #666;
font-size: 14px;
font-weight: bold;
height: 31px;
line-height: 31px;
padding-left: 36px;
}
.ke-dialog-row {
margin-bottom: 10px;
}
.ke-dialog-footer {
font: 12px/1 "sans serif",tahoma,verdana,helvetica;
text-align: right;
padding:0 0 5px 0;
background-color: #FFF;
width: 100%;
}
.ke-dialog-preview,
.ke-dialog-yes {
margin: 5px;
}
.ke-dialog-no {
margin: 5px 10px 5px 5px;
}
.ke-dialog-mask {
background-color:#FFF;
filter:alpha(opacity=50);
opacity:0.5;
}
.ke-button-common {
background: url(background.png) no-repeat;
cursor: pointer;
height: 23px;
line-height: 23px;
overflow: visible;
display: inline-block;
vertical-align: top;
cursor: pointer;
}
.ke-button-outer {
background-position: 0 -25px;
padding: 0;
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
}
.ke-button {
background-position: right -25px;
padding: 0 14px 0 12px;
margin: 0 0 0 2px;
font-family: "sans serif",tahoma,verdana,helvetica;
border: 0 none;
color: #333;
font-size: 12px;
text-decoration: none;
}
/* inputbox */
.ke-input-text {
background-color:#FFFFFF;
font-family: "sans serif",tahoma,verdana,helvetica;
font-size: 12px;
line-height: 17px;
height: 17px;
padding: 2px 4px;
border-color: #848484 #E0E0E0 #E0E0E0 #848484;
border-style: solid;
border-width: 1px;
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
}
.ke-input-number {
width: 50px;
}
.ke-input-color {
border: 1px solid #A0A0A0;
background-color: #FFFFFF;
font-size: 12px;
width: 60px;
height: 20px;
line-height: 20px;
padding-left: 5px;
overflow: hidden;
cursor: pointer;
display: -moz-inline-stack;
display: inline-block;
vertical-align: middle;
zoom: 1;
*display: inline;
}
.ke-upload-button {
position: relative;
}
.ke-upload-area {
position: relative;
overflow: hidden;
margin: 0;
padding: 0;
*height: 25px;
}
.ke-upload-area .ke-upload-file {
position: absolute;
font-size: 60px;
top: 0;
right: 0;
padding: 0;
margin: 0;
z-index: 811212;
border: 0 none;
opacity: 0;
filter: alpha(opacity=0);
}
/* tabs */
.ke-tabs {
font: 12px/1 "sans serif",tahoma,verdana,helvetica;
border-bottom:1px solid #A0A0A0;
padding-left:5px;
margin-bottom:20px;
}
.ke-tabs-ul {
list-style-image:none;
list-style-position:outside;
list-style-type:none;
margin:0;
padding:0;
}
.ke-tabs-li {
position: relative;
border: 1px solid #A0A0A0;
background-color: #F0F0EE;
margin: 0 2px -1px 0;
padding: 0 20px;
float: left;
line-height: 25px;
text-align: center;
color: #555555;
cursor: pointer;
}
.ke-tabs-li-selected {
background-color: #FFF;
border-bottom: 1px solid #FFF;
color: #000;
cursor: default;
}
.ke-tabs-li-on {
background-color: #FFF;
color: #000;
}
/* progressbar */
.ke-progressbar {
position: relative;
margin: 0;
padding: 0;
}
.ke-progressbar-bar {
border: 1px solid #6FA5DB;
width: 80px;
height: 5px;
margin: 10px 10px 0 10px;
padding: 0;
}
.ke-progressbar-bar-inner {
width: 0;
height: 5px;
background-color: #6FA5DB;
overflow: hidden;
margin: 0;
padding: 0;
}
.ke-progressbar-percent {
position: absolute;
top: 0;
left: 40%;
display: none;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+58
View File
@@ -0,0 +1,58 @@
/**
* date:2019/08/16
* author:Mr.Chung
* description:此处放layui自定义扩展
* version:2.0.4
*/
window.rootPath = (function (src) {
src = document.scripts[document.scripts.length - 1].src;
return src.substring(0, src.lastIndexOf("/") + 1);
})();
layui.config({
base: rootPath + "lay-module/",
version: true
}).extend({
xphp: "layuimini/xphp", // layuimini后台扩展
miniAdmin: "layuimini/miniAdmin", // layuimini后台扩展
miniMenu: "layuimini/miniMenu", // layuimini菜单扩展
miniTab: "layuimini/miniTab", // layuimini tab扩展
miniTheme: "layuimini/miniTheme", // layuimini 主题扩展
step: 'step-lay/step', // 分步表单扩展
treetable: 'treetable-lay/treetable', //table树形扩展
tableSelect: 'tableSelect/tableSelect', // table选择扩展
echarts: 'echarts/echarts', // echarts图表扩展
echartsTheme: 'echarts/echartsTheme', // echarts图表主题扩展
wangEditor: 'wangEditor/wangEditor', // wangEditor富文本扩展
layarea: 'layarea/layarea', // 省市县区三级联动下拉选择器
selectM: 'selectM/selectM',//下拉多选
selectN: 'selectN/selectN',//多个select循环无限下级选
numinput: 'numinput/numinput',//数字输入
regionCheckBox: 'regionCheckBox/regionCheckBox',//省市县选择
openTable: 'openTable/openTable',//用途不大
iPicker: 'ipicker/iPicker',//多个panel无限循环下级多选
layselect: 'layselect/layselect',//下拉单选,支持联动
selectY: 'selectY/selectY',//只需要pid,id,name,就可以无限级选择
selectY2: 'selectY/selectY2',//只需要pid,id,name,就可以无限级选择
tableFilter: 'tablefilter/tableFilter',//列数值筛选
sliderVerify: 'sliderVerify/sliderVerify',//滑动验证
cascader: 'cascader/cascader',//级联选择组件
checkbox: 'checkbox/checkbox',//多选美化
dropdownTable: 'dropdownTable/dropdownTable',//下拉表格选择组件
hashes: 'hashes/hashes',//hash:md5 sha1 sha256 sha512 crc32
inputTag: 'inputTag/inputTag',//标签输入
jmSheet: 'jmSheet/jmSheet',//底部弹出sheet
location: 'location/location',//百度地图经纬度
locationX: 'location/locationX',//百度地图经纬度x
tableMerge: 'tableMerge/tableMerge',//表格列合并
textool: 'textool/textool.min',//文本输入工具
moreMenus: 'moreMenus/moreMenus',//更多/隐藏
sliderTime: 'sliderTime/sliderTime',//时间范围选择
tableEdit: 'tableTree/tableEdit',//表格编辑
tableTree: 'tableTree/tableTree',//表格树
transferTable: 'transferTable/transferTable',//穿梭
notice: "notice/notice", // layuimini后台扩展
mods: "mods/mods", // jsannotice
passwordIntensity: "passwordIntensity/passwordIntensity", // jsannotice
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
.checkBox .block{float:left; margin:5px;padding:6px 15px;height:18px;text-align:center; border:1px solid #ccc;position:relative;cursor:pointer;overflow:hidden;}
.checkBox .block .choice{position:absolute;right:0px;bottom:0px;display:none;}
.checkBox .block.on{border:1px solid #1E9FFF;}
.checkBox .block.on .choice{position:absolute;right:0px;bottom:0px;display:block;}
.checkBox .block.on .choice .triangle{position:absolute;right:0px;bottom:0px;border-bottom:18px solid #1E9FFF;border-left: 18px solid transparent;}
.checkBox .block.on .choice .right{position:absolute;right:5px;bottom:5px;width:10px;height:10px;}
.checkBox .block .del{width:18px; height:18px; background:#fff; border:0px solid #ccc; border-radius:3px; overflow:hidden; cursor:pointer; position:absolute; bottom:-20px; right:0px; transition: background .3s ease, border .2s ease, bottom .2s ease;display:block;}
.checkBox .block .del:hover{background:#FF5722; border:1px solid #FF5722;}
.checkBox .block:hover .del{bottom:0px;}
.checkBox .block.on .del{display:none}
+69
View File
@@ -0,0 +1,69 @@
layui.define('jquery', function(exports){
"use strict";
var $ = layui.$
,hint = layui.hint();
var CheckBox = function(options){
this.options = options;
};
//初始化
CheckBox.prototype.init = function(elem){
var that = this;
elem.addClass('checkBox'); //添加checkBox样式
that.checkbox(elem);
};
//树节点解析
CheckBox.prototype.checkbox = function(elem,children){
var that = this, options = that.options;
var nodes = children || options.nodes;
layui.each(nodes, function(index, item){
var li = $(['<li class="block'+(item.on?' on':'')+'" value="'+item.name+'" onmouseover="layui.layer.tips(\''+item.type+'\',this,{tips:2})" onmouseout="layui.layer.closeAll(\'tips\');">'+item.name,'<i class="choice"><i class="triangle"></i><i class="right layui-icon layui-icon-ok"></i></i><i class="del"><i class="layui-icon layui-icon-delete"></i></i><span class="hide">'+(item.on?'<input type="hidden" name="'+item.name+'" value="'+item.type+'">':'')+'</span></li>'].join(''));
elem.append(li);
//触发点击节点回调
typeof options.click === 'function' && that.click(li, item);
//触发删除节点回调
typeof options.del === 'function' && that.del(li, item);
});
};
//点击节点回调
CheckBox.prototype.click = function(elem, item){
var that = this, options = that.options;
elem.on('click', function(e){
elem.toggleClass("on");
if(elem.hasClass("on")){
item.on = true;
elem.children("span.hide").html('<input type="hidden" name="'+item.name+'" value="'+item.type+'">');
}else{
item.on = false;
elem.children("span.hide").html('');
}
layui.stope(e);
options.click(item);
});
};
//点击节点回调
CheckBox.prototype.del = function(elem, item){
var that = this, options = that.options;
elem.children('i.del').on('click', function(e){
var index = layer.confirm('确定删除 ['+item.name+'] 吗?', {
btn: ['删除','取消']
}, function(){
layer.close(index);
if(options.del(item)){
elem.closest(".block").remove();
layui.stope(e);
}
});
return false;
});
};
//暴露接口
exports('checkbox', function(options){
var checkbox = new CheckBox(options = options || {});
var elem = $(options.elem);
if(!elem[0]){
return hint.error('layui.checkbox 没有找到'+ options.elem +'元素');
}
checkbox.init(elem);
});
}).link(layui.cache.base+"checkbox/checkbox.css?v="+(new Date).getTime());
@@ -0,0 +1,677 @@
layui.define(['jquery', 'dropdown', 'table', 'form'], function (exports) {
"use strict";
var dropdown = layui.dropdown, //下拉菜单
table = layui.table, //table组件
$ = layui.jquery, //jQuery
form = layui.form, //表单
moduleName = 'dropdownTable', //模块名
dropdownTable = {
version: '1.0.4',
config: {
selectType: 'radio',
emptyMsg: '点击此处选择'
},
index: layui[moduleName] ? (layui[moduleName].index + 10000) : 0,
set: function (options) {
this.config = $.extend(true, {}, that.config, options);
let config = this.config,
selectType = config.selectType,
selectField = { type: selectType, fixed: 'left' },
cols = config?.selectTable?.cols ?? [[]];
cols.forEach((item) => {
if (JSON.stringify(item).indexOf(JSON.stringify(selectField)) < 0) {
item.splice(0, 0, selectField);
}
});
return that;
}
},
//操作当前实例
thisModule = function () {
let that = this,
options = that.config,
id = options.id || that.index;
thisModule.that[id] = that; //记录当前实例对象
return {
config: options,
reload: function (options) {
that.reload.call(that, options);
}
};
},
//构造器
Class = function (options) {
let index = ++dropdownTable.index;
this.index = index;
this.tableId = 'dropdown-select-table-' + index; //初始化当前下拉表格的ID
this.dropdownId = 'dropdown-' + index; //初始化当前下拉组件的ID
//其中selectedIds为初始化被选择的值,selectedDisplayValues为初始化被选中值的显示值
this.config = $.extend(true, {}, dropdownTable.config, options, {
selectedIds: [],
selectedDisplayValues: []
});
let config = this.config,
selectType = config.selectType,
selectField = { type: selectType, fixed: 'left' },
selectTableCols = config?.selectTable?.cols ?? [[]];
if (selectType === 'checkbox') {
selectTableCols.forEach((item) => {
if (JSON.stringify(item).indexOf(JSON.stringify(selectField)) < 0) {
item.splice(0, 0, selectField);
}
});
}
this.render();
};
//重载表格实例
Class.prototype.reloadSelectTable = function (selectTableConfig) {
let config = this.config;
layui.each(selectTableConfig, function (key, item) {
if (layui.type(item) === 'array') {
delete config.selectTable[key];
}
});
$.extend(true, config.selectTable, selectTableConfig);
this.clearSelected();
};
//清空选中
Class.prototype.clearSelected = function () {
let config = this.config,
bindInput = config.bindInput;
$(bindInput).val("");
$(bindInput)[0].dataset.displayValue = '';
$.extend(config, { selectedIds: [], selectedDisplayValues: [] });
this.setSelectedDisplayAndValue();
}
//渲染
Class.prototype.render = function () {
let that = this,
options = that.config,
_this = options.elem = $(options.elem);
if (!_this[0]) {
return;
}
that.initElemArea();
that.iniDropdown();
};
//初始化绑定元素区域
Class.prototype.initElemArea = function () {
let that = this,
config = this.config,
elem = config.elem,
searchName = this.config?.searchName ?? 'keywords';
$(elem).css({
'display': 'inline-block',
'width': '80%',
'height': '100%',
'min-height': '35px',
'border': '1px solid #eee',
'line-height': '35px',
'box-sizing': 'border-box',
'padding': '0 10px',
'cursor': 'pointer'
});
$(elem).hover(() => {
$(elem).css({ 'border-color': '#e2e2e2' });
}, () => {
$(elem).css({ 'border-color': '#eee' });
});
let selectButton = $("<button type='button' class='layui-btn layui-btn-primary'>选择</button>")
selectButton.css({
'display': 'inline-block',
'width': '20%',
'min-width': '45px',
'height': '100%',
'box-sizing': 'border-box',
'font-size': '12px',
'padding': '0',
'line-height': '36px'
});
if (config?.needPopup ?? true) {
$(elem).after(selectButton);
} else {
$(elem).css({ 'width': '100%' });
}
let selectContent = `
<div class="select-container" >
<div class="layui-row">
<div class="layui-col-md7 table-container">
<div class="layui-bg-green header">
<div class="layui-font-14">选择</div>
<form class="layui-form" style="float: right;" lay-filter="data-table-search-form">
<div class="layui-form-item" style="margin:0;">
<div class="layui-input-inline">
<input type="text" id="data_table_${searchName}" name="data_table_${searchName}" placeholder="请输入您要搜索的内容" class="layui-input">
</div>
<div class="layui-inline">
<button id="data-table-search-button" type="button" class="layui-btn layui-btn-primary" style="background-color:white"><i class="layui-icon layui-icon-search"></i></button>
</div>
</div>
</form>
</div>
<!--表格-->
<div class="table-item">
<table class="layui-hide" id="data-table" lay-filter="data-table"></table>
</div>
</div>
<div class="layui-col-md5 table-container">
<div class="layui-bg-green header">
<div class="layui-font-14">选择结果</div>
</div>
<div class="table-item">
<table class="layui-hide" id="selected-table" lay-filter="selected-table"></table>
<script type="text/html" id="selected-table-opt-bar">
<div class="layui-clear-space">
<a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">移除</a>
</div>
</script>
</div>
</div>
</div>
</div>
<style>
.select-container{
width:100%;
padding:10px;
box-sizing:border-box;
}
.table-container {
box-sizing: border-box;
padding-right: 10px;
}
.table-container>.header {
width: 100%;
display: table;
padding: 5px 10px;
box-sizing: border-box;
min-height: 50px;
}
.table-container>.header>* {
display: table-cell;
vertical-align: middle;
}
.table-container>.table-item {
margin-top: 20px;
}
</style>
`
selectButton.click(() => {
layer.open({
title: '选择',
type: 1,
area: ['70%', '80%'],
maxmin: true,
btn: ['确认', '取消'],
content: selectContent,
success: () => {
renderSelectedTable();
renderDataTable();
bindTableEvent();
initSelectedTable();
bindDataTableSearchFormEvent();
},
yes: index => {
let selectedData = table.getData('selected-table') ?? [];
let selectedIds = selectedData.map(item => item.id);
config.selectedIds = selectedIds;
config.selectedDisplayValues = selectedData.map(item => item.displayValue);
that.setSelectedDisplayAndValue();
layer.close(index);
let onSelected = config.onSelected;
if ($.isFunction(onSelected)) {
onSelected(selectedIds);
}
}
});
});
function renderDataTable() {
let tableNeedConfig = {
id: 'data-table',
elem: '#data-table',
done: function (res) {
setDataTableSelected();
}
},
tableConfig = $.extend({}, config.selectTable, tableNeedConfig);
table.render(tableConfig);
}
function renderSelectedTable() {
table.render({
elem: '#selected-table',
cols: [
[
{ field: 'id', title: 'ID', width: 80, sort: true },
{ field: 'displayValue', title: '值' },
{ field: 'originValue', title: '原始值', hide: true },
{ fixed: 'right', title: '操作', width: 70, toolbar: '#selected-table-opt-bar' }
]
],
data: []
});
}
function bindDataTableSearchFormEvent() {
$('#data-table-search-button').click(() => {
let where = {},
searchValue = $('#data_table_' + searchName).val();
where[searchName] = searchValue;
table.reloadData('data-table', { page: { curr: 1 }, where: where });
});
}
function bindTableEvent() {
table.on('row(data-table)', (obj) => {
let data = obj.data;
selectedTableReload({
'id': data[config.selectTable.uniqueId],
'displayValue': data[config.selectTable.displayField],
'originValue': JSON.stringify(data)
});
});
table.on('tool(selected-table)', obj => {
if (obj.event === 'del') {
obj.del();
setDataTableSelected();
}
});
}
function selectedTableReload(selectedData) {
let originData = table.getData('selected-table') ?? [];
if (originData.map(item => item.id).includes(selectedData.id)) {
originData = originData.filter(item => item.id !== selectedData.id);
} else {
if (config.selectType === 'radio') {
originData = [];
}
originData.push(selectedData)
}
table.reload('selected-table', {
data: originData
});
setDataTableSelected();
}
function setDataTableSelected() {
let selectedIds = (table.getData('selected-table') ?? []).map(item => item.id + '');
let data = (table.getData('data-table') ?? []);
data.forEach((item, index) => {
if (config.selectType === 'checkbox') {
table.setRowChecked('data-table', {
type: 'checkbox',
index: index,
checked: selectedIds.includes(item.id + '')
});
} else if (selectedIds.includes(item.id + '')) {
table.setRowChecked('data-table', {
type: 'radio',
index: index,
checked: true
});
}
});
}
function initSelectedTable() {
let bindInput = config.bindInput,
bindInputValue = $(bindInput).val() ?? '',
bindInputDisplayValue = $(bindInput)[0].dataset.displayValue ?? '';
config.selectedIds = bindInputValue.split("$").filter(item => item !== '');
config.selectedDisplayValues = bindInputDisplayValue.split("$").filter(item => item !== '');
config.selectedIds.forEach((id, index) => {
selectedTableReload({
'id': id,
'displayValue': config.selectedDisplayValues[index]
});
});
}
}
//初始化下拉组件
Class.prototype.iniDropdown = function () {
let that = this,
config = that.config,
elem = config.elem;
dropdown.render({
id: config.id ?? that.index,
elem: elem,
trigger: 'click',
content: that.iniSelectTableHtml(),
style: config?.style ?? 'min-width:450px;box-sizing:border-box; padding:10px;width:' + $(elem).width() + 'px',
ready: () => {
that.iniSelectTable();
that.bindRowCheckToSelectTable();
that.bindSelectBoxEventToSelectTable();
that.bindSearchToSelectTable();
}
});
};
//初始化table的html文件
Class.prototype.iniSelectTableHtml = function () {
let index = this.index,
tableId = this.tableId,
searchName = this.config?.searchName ?? 'keywords',
selectTableSearchFormId = 'select-table-search-' + index,
selectTableSearchButtonId = 'select-table-search-button-' + index;
$.extend(this.config, {
selectTableSearchFormId: selectTableSearchFormId,
selectTableSearchButtonId: selectTableSearchButtonId
});
return [
'<div class="chosen-window">',
'<script type="text/html" id="' + selectTableSearchFormId + '">',
'<form class="layui-form layui-row">',
'<div class="layui-inline">',
'<div class="layui-input-inline">',
'<input type="text" name="' + searchName + '" placeholder="请输入要搜索的内容" class="layui-input">',
'</div>',
'</div>',
'<div class="layui-inline"><button class="layui-btn" lay-submit lay-filter="' + selectTableSearchButtonId + '">搜索</button></div>',
'</form>',
'</script>',
'<table class="layui-hide" id="' + tableId + '" lay-filter="' + tableId + '"></table>',
'</div>',
].join('');
}
//初始化表格
Class.prototype.iniSelectTable = function () {
let that = this,
config = that.config,
tableId = that.tableId,
selectTable = config.selectTable,
tableNeedConfig = {
id: tableId,
elem: '#' + tableId,
toolbar: '#' + config.selectTableSearchFormId,
defaultToolbar: ['filter'],
done: function (res) {
that.iniDefaultSelected(res.data)
}
},
tableConfig = $.extend({}, selectTable, tableNeedConfig);
table.render(tableConfig);
};
//处理默认选中值的问题
Class.prototype.iniDefaultSelected = function (tableData = []) {
let that = this,
tableId = that.tableId,
config = that.config,
selectType = config.selectType,
bindInput = config.bindInput,
bindInputValue = $(bindInput).val() ?? '',
bindInputDisplayValue = $(bindInput)[0].dataset.displayValue ?? '';
config.selectedIds = bindInputValue.split("$").filter(item => item !== '');
config.selectedDisplayValues = bindInputDisplayValue.split("$").filter(item => item !== '');
if (tableData.length === 0) {
that.setSelectedDisplayAndValue();
return;
}
table.setRowChecked(tableId, { index: 'all', checked: false });
let selectedIds = config.selectedIds;
if (selectedIds.length > 0) {
let tableIdData = tableData.map(item => item[config.selectTable.uniqueId].toString());
if (selectType === 'radio' && selectedIds.length === 1) {
let selectedItemIndex = tableIdData.indexOf(selectedIds[0].toString());
if (selectedItemIndex >= 0) {
table.setRowChecked(tableId, { type: selectType, index: selectedItemIndex, checked: true })
}
} else {
tableIdData.forEach(function (item, itemIndex) {
table.setRowChecked(tableId, {
type: selectType,
index: itemIndex,
checked: selectedIds.includes(item)
});
});
}
}
that.setSelectedDisplayAndValue();
}
//处理选择框事件
Class.prototype.bindSelectBoxEventToSelectTable = function () {
let that = this,
options = that.config,
selectType = options.selectType,
uniqueId = options.selectTable.uniqueId,
displayField = options.selectTable.displayField,
tableId = that.tableId;
if (selectType === 'radio') { //单选
table.on('radio(' + tableId + ')', function (obj) {
dealRadioSelectedData(obj.checked, obj.data);
});
} else { //复选框
table.on('checkbox(' + tableId + ')', function (obj) {
let eventType = obj.type,
checked = obj.checked;
if (eventType === 'all') {
table.getData(tableId).forEach(function (rowData) {
dealCheckboxSelectedData(checked, rowData);
});
}
if (eventType === 'one') {
dealCheckboxSelectedData(checked, obj.data);
}
});
}
function dealRadioSelectedData(checked, rowData) {
let rowId = rowData[uniqueId].toString();
that.config.selectedIds = [];
that.config.selectedDisplayValues = [];
if (checked) {
that.config.selectedIds.push(rowId);
that.config.selectedDisplayValues.push(rowData[displayField]);
}
that.setSelectedDisplayAndValue();
}
function dealCheckboxSelectedData(checked, rowData) {
let rowId = rowData[uniqueId].toString();
//处理选中
if (checked && !that.config.selectedIds.includes(rowId)) {
that.config.selectedIds.push(rowId);
that.config.selectedDisplayValues.push(rowData[displayField]);
}
//处理未选中
if (!checked) {
let cancelIndex = that.config.selectedIds.indexOf(rowId);
if (rowId > -1) {
that.config.selectedIds.splice(cancelIndex, 1);
that.config.selectedDisplayValues.splice(cancelIndex, 1);
}
}
that.setSelectedDisplayAndValue();
}
}
//绑定行点击事件到选择表中
Class.prototype.bindRowCheckToSelectTable = function () {
let that = this,
tableId = that.tableId,
options = that.config,
selectType = options.selectType,
uniqueId = options.selectTable.uniqueId,
displayField = options.selectTable.displayField;
table.on('row(' + tableId + ')', function (obj) {
let rowId = obj.data[uniqueId].toString(),
checked;
if (!that.config.selectedIds.includes(rowId)) {
if (selectType === 'radio') {
that.config.selectedIds = [];
that.config.selectedDisplayValues = [];
}
that.config.selectedIds.push(rowId);
that.config.selectedDisplayValues.push(obj.data[displayField]);
checked = true;
} else {
let cancelSelectedIdIndex = that.config.selectedIds.indexOf(rowId);
that.config.selectedIds.splice(cancelSelectedIdIndex, 1);
that.config.selectedDisplayValues.splice(cancelSelectedIdIndex, 1);
checked = false;
}
obj.setRowChecked({
type: selectType,
checked: checked
});
//加入选中事件
let onSelected = options.onSelected;
if (checked && $.isFunction(onSelected)) {
onSelected(new Array(obj.data[options.selectTable.uniqueId]));
}
that.setSelectedDisplayAndValue();
});
};
//绑定表格的搜索事件
Class.prototype.bindSearchToSelectTable = function () {
let tableId = this.tableId,
selectTableSearchButtonId = this.config.selectTableSearchButtonId;
form.on('submit(' + selectTableSearchButtonId + ')', function (data) {
table.reloadData(tableId, { page: { curr: 1 }, where: data.field });
return false;
});
}
//设置显示值和实际存储值
Class.prototype.setSelectedDisplayAndValue = function () {
let that = this,
tableId = that.tableId,
options = that.config,
elem = options.elem,
bindInput = options.bindInput,
selectedIds = options?.selectedIds ?? [],
selectDisplayValues = options.selectedDisplayValues,
emptyMsg = options.emptyMsg;
elem.find("span").remove();
if (selectedIds.length > 0 && selectedIds.length === selectDisplayValues.length) {
selectedIds.forEach((item, itemIndex) => {
let selectedDisplayValue = selectDisplayValues[itemIndex],
closeObject = $('<span style="margin-left:5px;color:#fff" data-selected-id="' + item + '">×<span>'),
displayHtml = [
'<span class="layui-badge layui-bg-green">' + selectedDisplayValue,
'</span>',
].join(''),
displayObject = $(displayHtml).append(closeObject);
displayObject.attr({
"style": "margin-left:5px;font-size:14px;padding:4px 6px"
});
//绑定鼠标事件
closeObject.on('mouseenter mouseleave', function (event) {
let optType = event.type,
fontColor = optType === 'mouseleave' ? 'white' : 'red';
$(this).attr({ "style": "color:" + fontColor + ";margin-left:5px;cursor:pointer" });
});
closeObject.on('click', function () {
let _this = this,
tableIdData = table.getData(tableId).map(item => item[options.selectTable.uniqueId]),
selectedId = _this.dataset.selectedId,
cancelSelectedIdIndex = that.config.selectedIds.indexOf(selectedId);
that.config.selectedIds.splice(cancelSelectedIdIndex, 1);
that.config.selectedDisplayValues.splice(cancelSelectedIdIndex, 1);
if (tableIdData.includes(selectedId)) {
if (options.selectType === 'radio') {
table.setRowChecked(tableId, {
type: 'radio',
index: 'all',
checked: false
});
} else {
table.setRowChecked(tableId, {
type: options.selectType,
index: tableIdData.indexOf(selectedId),
checked: false
});
}
}
that.setSelectedDisplayAndValue();
});
elem.append(displayObject);
});
} else {
elem.append('<span class="layui-font-gray layui-font-14" style="margin-left:5px;">' + emptyMsg + '</span>');
}
$(bindInput).val(selectedIds.join("$"));
$(bindInput)[0].dataset.displayValue = selectDisplayValues.join("$");
}
//记录所有实例
thisModule.that = {}; //记录所有实例对象
//获取当前实例对象
thisModule.getThis = function (id) {
let that = thisModule.that[id];
if (!that) {
hint.error(id ? (moduleName + ' instance with ID \'' + id + '\' not found') : 'ID argument required');
}
return that;
}
//重载实例
dropdownTable.reloadSelectTable = function (id, selectTableConfig) {
let that = thisModule.getThis(id);
that.reloadSelectTable(selectTableConfig);
return thisModule.call(that);
}
//请空已选择
dropdownTable.clearSelected = function (id) {
let that = thisModule.getThis(id);
that.clearSelected();
}
//核心入口
dropdownTable.render = function (options) {
let inst = new Class(options);
if (dropdownTable.index === 1) {
console.log("欢迎使用Hg科技的dropdownTable组件,version:" + dropdownTable.version + ",期待您的建议!");
}
inst.iniDefaultSelected();
return thisModule.call(inst);
}
exports(moduleName, dropdownTable);
});
File diff suppressed because one or more lines are too long
@@ -0,0 +1,492 @@
layui.define(function(exports) {
exports('echartsTheme',
{
"color": [
"#3fb1e3",
"#6be6c1",
"#626c91",
"#a0a7e6",
"#c4ebad",
"#96dee8"
],
"backgroundColor": "rgba(252,252,252,0)",
"textStyle": {},
"title": {
"textStyle": {
"color": "#666666"
},
"subtextStyle": {
"color": "#999999"
}
},
"line": {
"itemStyle": {
"normal": {
"borderWidth": "3"
}
},
"lineStyle": {
"normal": {
"width": "4"
}
},
"symbolSize": "10",
"symbol": "emptyCircle",
"smooth": true
},
"radar": {
"itemStyle": {
"normal": {
"borderWidth": "3"
}
},
"lineStyle": {
"normal": {
"width": "4"
}
},
"symbolSize": "10",
"symbol": "emptyCircle",
"smooth": true
},
"bar": {
"itemStyle": {
"normal": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
},
"emphasis": {
"barBorderWidth": 0,
"barBorderColor": "#ccc"
}
}
},
"pie": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"scatter": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"boxplot": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"parallel": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"sankey": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"funnel": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"gauge": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
},
"emphasis": {
"borderWidth": 0,
"borderColor": "#ccc"
}
}
},
"candlestick": {
"itemStyle": {
"normal": {
"color": "#e6a0d2",
"color0": "transparent",
"borderColor": "#e6a0d2",
"borderColor0": "#3fb1e3",
"borderWidth": "2"
}
}
},
"graph": {
"itemStyle": {
"normal": {
"borderWidth": 0,
"borderColor": "#ccc"
}
},
"lineStyle": {
"normal": {
"width": "1",
"color": "#cccccc"
}
},
"symbolSize": "10",
"symbol": "emptyCircle",
"smooth": true,
"color": [
"#3fb1e3",
"#6be6c1",
"#626c91",
"#a0a7e6",
"#c4ebad",
"#96dee8"
],
"label": {
"normal": {
"textStyle": {
"color": "#ffffff"
}
}
}
},
"map": {
"itemStyle": {
"normal": {
"areaColor": "#eeeeee",
"borderColor": "#aaaaaa",
"borderWidth": 0.5
},
"emphasis": {
"areaColor": "rgba(63,177,227,0.25)",
"borderColor": "#3fb1e3",
"borderWidth": 1
}
},
"label": {
"normal": {
"textStyle": {
"color": "#ffffff"
}
},
"emphasis": {
"textStyle": {
"color": "rgb(63,177,227)"
}
}
}
},
"geo": {
"itemStyle": {
"normal": {
"areaColor": "#eeeeee",
"borderColor": "#aaaaaa",
"borderWidth": 0.5
},
"emphasis": {
"areaColor": "rgba(63,177,227,0.25)",
"borderColor": "#3fb1e3",
"borderWidth": 1
}
},
"label": {
"normal": {
"textStyle": {
"color": "#ffffff"
}
},
"emphasis": {
"textStyle": {
"color": "rgb(63,177,227)"
}
}
}
},
"categoryAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#999999"
}
},
"splitLine": {
"show": true,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"valueAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#999999"
}
},
"splitLine": {
"show": true,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"logAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#999999"
}
},
"splitLine": {
"show": true,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"timeAxis": {
"axisLine": {
"show": true,
"lineStyle": {
"color": "#cccccc"
}
},
"axisTick": {
"show": false,
"lineStyle": {
"color": "#333"
}
},
"axisLabel": {
"show": true,
"textStyle": {
"color": "#999999"
}
},
"splitLine": {
"show": true,
"lineStyle": {
"color": [
"#eeeeee"
]
}
},
"splitArea": {
"show": false,
"areaStyle": {
"color": [
"rgba(250,250,250,0.05)",
"rgba(200,200,200,0.02)"
]
}
}
},
"toolbox": {
"iconStyle": {
"normal": {
"borderColor": "#999999"
},
"emphasis": {
"borderColor": "#666666"
}
}
},
"legend": {
"textStyle": {
"color": "#999999"
}
},
"tooltip": {
"axisPointer": {
"lineStyle": {
"color": "#cccccc",
"width": 1
},
"crossStyle": {
"color": "#cccccc",
"width": 1
}
}
},
"timeline": {
"lineStyle": {
"color": "#626c91",
"width": 1
},
"itemStyle": {
"normal": {
"color": "#626c91",
"borderWidth": 1
},
"emphasis": {
"color": "#626c91"
}
},
"controlStyle": {
"normal": {
"color": "#626c91",
"borderColor": "#626c91",
"borderWidth": 0.5
},
"emphasis": {
"color": "#626c91",
"borderColor": "#626c91",
"borderWidth": 0.5
}
},
"checkpointStyle": {
"color": "#3fb1e3",
"borderColor": "rgba(63,177,227,0.15)"
},
"label": {
"normal": {
"textStyle": {
"color": "#626c91"
}
},
"emphasis": {
"textStyle": {
"color": "#626c91"
}
}
}
},
"visualMap": {
"color": [
"#2a99c9",
"#afe8ff"
]
},
"dataZoom": {
"backgroundColor": "rgba(255,255,255,0)",
"dataBackgroundColor": "rgba(222,222,222,1)",
"fillerColor": "rgba(114,230,212,0.25)",
"handleColor": "#cccccc",
"handleSize": "100%",
"textStyle": {
"color": "#999999"
}
},
"markPoint": {
"label": {
"normal": {
"textStyle": {
"color": "#ffffff"
}
},
"emphasis": {
"textStyle": {
"color": "#ffffff"
}
}
}
}
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,87 @@
@keyframes fariy-fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fairy-tag-container {
width: auto;
min-height: 100px;
padding: 5px;
border: 1px solid #e6e6e6;
background-color: #ffffff;
}
.fairy-tag-container:hover {
border-color: #d2d2d2;
}
.fairy-tag-container span.fairy-tag {
float: left;
font-size: 13px;
padding: 5px 8px;
margin-right: 5px;
margin-bottom: 5px;
border-radius: 2px;
line-height: 16px;
}
.fairy-tag-container span.fairy-tag a {
font-size: 11px;
font-weight: bolder;
color: #ffffff;
text-decoration: none;
margin-left: 6px;
}
.fairy-tag-container span.fairy-tag a:hover {
cursor: pointer;
}
.fairy-tag-container span.fairy-bg-red {
background-color: #FF5722;
}
.fairy-tag-container span.fairy-bg-orange {
background-color: #FFB800;
}
.fairy-tag-container span.fairy-bg-green {
background-color: #009688;
}
.fairy-tag-container span.fairy-bg-cyan {
background-color: #2F4056;
}
.fairy-tag-container span.fairy-bg-blue {
background-color: #1E9FFF;
}
.fairy-tag-container span.fairy-bg-black {
background-color: #393D49;
}
.fairy-tag-container span.fairy-bg-red,
.fairy-tag-container span.fairy-bg-orange,
.fairy-tag-container span.fairy-bg-green,
.fairy-tag-container span.fairy-bg-cyan,
.fairy-tag-container span.fairy-bg-blue,
.fairy-tag-container span.fairy-bg-black {
color: #ffffff;
}
.fairy-tag-container .fairy-anim-fadein {
animation: fariy-fadein 0.3s both;
}
.fairy-tag-container .fairy-tag-input[type='text'] {
width: 80px;
font-size: 13px;
padding: 6px;
background: transparent;
border: 0 none;
outline: 0;
}
.fairy-tag-container .fairy-tag-input[type='text']:focus::-webkit-input-placeholder {
color: transparent;
}
.fairy-tag-container .fairy-tag-input[type='text']:focus:-moz-placeholder {
color: transparent;
}
.fairy-tag-container .fairy-tag-input[type='text']:focus:-moz-placeholder {
color: transparent;
}
.fairy-tag-container .fairy-tag-input[type='text']:focus:-ms-input-placeholder {
color: transparent;
}
/*# sourceMappingURL=inputTag.css.map */
+150
View File
@@ -0,0 +1,150 @@
/*
* Name: inputTag
* Author: cshaptx4869
* Project: https://github.com/cshaptx4869/inputTag
*/
(function (define) {
define(['jquery'], function ($) {
"use strict";
class InputTag {
options = {
elem: '.fairy-tag-input',
theme: ['fairy-bg-red', 'fairy-bg-orange', 'fairy-bg-green', 'fairy-bg-cyan', 'fairy-bg-blue', 'fairy-bg-black'],
data: [],
removeKeyNum: 8,
createKeyNum: 13,
permanentData: [],
};
get elem() {
return $(this.options.elem);
}
get copyData() {
return [...this.options.data];
}
constructor(options) {
this.render(options);
}
render(options) {
this.init(options);
this.listen();
}
init(options) {
var spans = '', that = this;
this.options = $.extend(this.options, options);
!this.elem.attr('placeholder') && this.elem.attr('placeholder', '添加标签');
$.each(this.options.data, function (index, item) {
spans += that.spanHtml(item);
});
this.elem.before(spans);
}
listen() {
var that = this;
this.elem.parent().on('click', 'a', function () {
that.removeItem($(this).parent('span'));
});
this.elem.parent().on('click', function () {
that.elem.focus();
});
this.elem.keydown(function (event) {
var keyNum = (event.keyCode ? event.keyCode : event.which);
if (keyNum === that.options.removeKeyNum) {
if (!that.elem.val().trim()) {
var closeItems = that.elem.parent().find('a');
if (closeItems.length) {
that.removeItem($(closeItems[closeItems.length - 1]).parent('span'));
event.preventDefault();
}
}
} else if (keyNum === that.options.createKeyNum) {
that.createItem();
event.preventDefault();
}
});
}
createItem() {
var value = this.elem.val().trim();
if (this.options.beforeCreate && typeof this.options.beforeCreate === 'function') {
var modifiedValue = this.options.beforeCreate(this.copyData, value);
if (typeof modifiedValue == 'string' && modifiedValue) {
value = modifiedValue;
} else {
value = '';
}
}
if (value) {
if (!this.options.data.includes(value)) {
this.options.data.push(value);
this.elem.before(this.spanHtml(value));
this.onChange(value, 'create');
}
}
this.elem.val('');
}
removeItem(target) {
var that = this;
var closeSpan = target.remove(),
closeSpanText = $(closeSpan).children('span').text();
var value = that.options.data.splice($.inArray(closeSpanText, that.options.data), 1);
value.length === 1 && that.onChange(value[0], 'remove');
}
randomColor() {
return this.options.theme[Math.floor(Math.random() * this.options.theme.length)];
}
spanHtml(value) {
return '<span class="fairy-tag fairy-anim-fadein ' + this.randomColor() + '">' +
'<span>' + value + '</span>' +
(this.options.permanentData.includes(value) ? '' : '<a href="#" title="删除标签">&times;</a>') +
'</span>';
}
onChange(value, type) {
this.options.onChange && typeof this.options.onChange === 'function' && this.options.onChange(this.copyData, value, type);
}
getData() {
return this.copyData;
}
clearData() {
this.options.data = [];
this.elem.prevAll('span.fairy-tag').remove();
}
}
return {
render(options) {
return new InputTag(options);
}
}
});
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
layui.link(layui.cache.base + "inputTag/inputTag.css?v="+(new Date).getTime());
var MOD_NAME = 'inputTag';
if (typeof module !== 'undefined' && module.exports) { //Node
module.exports = factory(require('jquery'));
} else if (window.layui && layui.define) {
layui.define('jquery', function (exports) { //layui加载
exports(MOD_NAME, factory(layui.jquery));
});
} else {
window[MOD_NAME] = factory(window.jQuery);
}
}));
File diff suppressed because one or more lines are too long
+80
View File
@@ -0,0 +1,80 @@
.jmSheet {
width: 100%;
background-color: #f8f8f8 !important;
}
.jmSheet li {
height: 55px;
border-bottom: 1px solid #eee;
display: flex;
/* justify-content: center; */
align-items: center;
box-sizing: border-box;
background-color: #fff;
gap: 10px;
padding: 0 10px;
}
.jmSheet li>.text {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.jmSheet li:hover {
cursor: pointer;
}
.jmSheet li:hover span {
color: #16b777;
}
.jmSheet li .img {
position: relative;
width: 24px;
height: 24px;
overflow: hidden;
border-radius: 5px;
}
.jmSheet li .img img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
}
.jmSheet li span {
font-size: 14px;
color: rgba(0, 0, 0, .8);
font-weight: 600;
}
.jmSheet li .desc {
font-weight: normal;
color: #c2c2c2;
font-size: 12px;
}
.jmSheet .close {
height: 55px;
margin-top: 8px;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
}
.jmSheet>h3 {
height: 40px;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
font-weight: normal;
font-size: 14px;
border-bottom: 1px solid #eee;
color: #00000080;
box-sizing: border-box;
}
+88
View File
@@ -0,0 +1,88 @@
layui.define(["jquery", "layer"], function (exports) {
"use strict";
var $ = layui.$;
var layer = layui.layer;
var jmSheet = {
open: function (obj) {
if (typeof obj.shadeClose === 'undefined') {
obj.shadeClose = true;
}
var align = "center"
if (typeof obj.align !== "undefined" && obj.align != "") {
switch (obj.align) {
case "left":
align = "flex-start";
break;
case "right":
align = "flex-end";
break;
default:
align = "center";
}
}
var html = "";
$.each(obj.content, function (k, v) {
var img = "";
if (typeof v.img !== 'undefined' && v.img != "") {
img = `<div class="img"><img src="${v.img}"></div>`;
}
html += `<li style="justify-content:${align};">
${img}
<div class="text">
<span>${v.text}</span>
<span class="desc">${v.desc || ''}</span>
</div>
</li>`
})
var btnClose = "";
var btnCloseSize = 0;
if (typeof obj.shadeClose !== 'undefined' && !obj.shadeClose) {
btnClose = `<a href="javascript:;" class="close">取消</a>`;
btnCloseSize = (55 + 8);
}
var title = "";
var titleSize = 0;
if (typeof obj.title !== 'undefined' && obj.title != "") {
title = `<h3>${obj.title}</h3>`;
titleSize = 40;
}
//弹出
var open = layer.open({
type: 1,
title: false,
closeBtn: 0,
offset: 'b',
anim: 'slideUp', // 从下往上
area: ['100%', titleSize + btnCloseSize + 55 * obj.content.length + 'px'],
shade: 0.1,
shadeClose: obj.shadeClose, // 是否点击遮罩关闭
id: obj.id || '',
content:
`<div class="jmSheet ${obj.addClass || ''}">
${title}
<ul>${html}</ul>
${btnClose}
</div>`
});
//关闭
$(`#layui-layer${open} .jmSheet .close`).on("click", function () {
layer.close(open);
})
//点击列表
$(`#layui-layer${open} .jmSheet`).on("click", "li", function () {
obj.callback($(this).index(), this, obj.content[$(this).index()]);
})
}
}
exports('jmSheet', jmSheet); // 输出模块
}).link(layui.cache.base+"jmSheet/jmSheet.css?v="+(new Date).getTime());
File diff suppressed because it is too large Load Diff
+177
View File
@@ -0,0 +1,177 @@
/**
* layselect 下拉框插件,只支持单选
* @author:Darker.Wang
* @version:1.1(优化增加数据内部控制元素默认选择)
* @version:1.2(优化支持指定请求头认证,修复元素默认选择优先级错乱)
* render参数{
* 属性:
* elem:元素ID,带#号必传
* url:请求路径的URL,必传
* data:请求url所携带的参数,可选
* type:请求方式,默认为get,可选
* option:元素数据,数组,用于不通过请求url获取数据,本地自动赋值,可选
* select:指定选中的索引项,可选,分组时索引为:groupNum-itemNum,如:1-2 表示第一组里的第二个元素
* 方法:
* format:格式化方法映射,将返回的Data元素映射乘标准格式
* success:成功回调,返回加载后的对象数组
* fail:失败回调,加载失败的处理
* onselect:点击选择时事件响应(如事件无响应,记得加lay-filter属性=id
* headers:可选,用于传递请求头认证,默认为:{Accept: "application/json; charset=utf-8"}
* contentType:可选,用于指定请求接口的数据类型,默认为:application/json
* }
* 请求返回需对象格式:rtvObj=option={status,code,codeName,select,...},不满足的通过format映射处理 status=0 时表示禁用
* 其他说明:
* 1、分组展示按照:groupNamegroupChildren 数组 [rtvObj]
* 2、暂不支持多选(后期版本规划:支持多选,在select标签上设置属性:multiple="true"
* 3、获取原始数据,可通过调用success得到,返回原始数据的集合
* 4、点击事件回调,可通过实现onselect 触发,参数为当前点击的值
* @param exports
* @returns 返回一个对象
* 码云地址:https://gitee.com/godbirds/layselect
*/
layui.define(['element','form','jquery'],function(exports){
var element = layui.element;
var form = layui.form;
var $ = layui.jquery;
var obj={
//{elem,url,data,type,format}
render:function(param){
var that = this;
var eid = param.elem;
that.selectValues=new Array();
if(param.type == null || param.type==undefined){
param.type = 'get';//默认get请求
}
if(param.data){
param.data = JSON.stringify(data);
}else{
param.data = {}
}
if(param.url == null || param.url == '' || param.url==undefined){
if(param.option == null || param.option == undefined){
param.option = new Array();//重新定义为了正常显示下拉框
}
that._init(eid,param,param.option);
}else{
$.ajax({
url: param.url,
type: param.type,
data: param.data,
async: 'false',
dataType: 'json',
headers: param.headers||{Accept: "application/json; charset=utf-8"},
contentType : param.contentType||'application/json',//指定json头
success: function(data){
that._init(eid,param,data)
},
error: function (e) {
//加载失败执行回调函数
console.log("Ajax request "+param.url+" error! ");
if(param.fail){
param.fail(e);//加载失败回调函数,请求URL时才会触发
}
}
});
}
/***
* 初始化:data=[{code,status,codeName,select,groupName,groupChildren}]
*/
that._init=function(eid,param,data){
$(eid).empty();//请求成功时清空
$(eid).prepend("<option value=''>请选择</option>");//添加第一个option值
var option = new Array();
if(param.format){//格式化
for (var i = 0; i < data.length; i++) {
var tdata = param.format(data[i]);
option.push({
code:tdata.code,
status:tdata.status||'1',
select:tdata.select||'false',
codeName:tdata.codeName,
groupName:tdata.groupName,
groupChildren:tdata.groupChildren
});
}
}else{//不格式化
for (var i = 0; i < data.length; i++) {
option.push({
code:data[i].code,
status:data[i].status||'1',
select:data[i].select||'false',
codeName:data[i].codeName,
groupName:data[i].groupName,
groupChildren:data[i].groupChildren
});
}
}
var isgroup = false;
for (var i = 0; i < option.length; i++) {
//分组
if(option[i].groupChildren != null && option[i].groupChildren != undefined &&
option[i].groupChildren != '' && option[i].groupChildren.length > 0){
isgroup = true;//分组标识
$(eid).append("<optgroup label='"+option[i].groupName+"'>");
option[i].groupChildren.forEach(function(item,index){
var status = "";var topborder ="",buttomborder="",checkoff="";
if(item.status && item.status == '0'){status = "disabled='disabled'";}//是否有效
$(eid).append("<option value='"+item.code+"' "+status+">"+item.codeName+"</option>");
//优先级:内部数据option中的选中标识优先级高于外部指定的优先级
if(item.select != undefined && (item.select == 'true' || item.select == true) && item.status != '0'){
that.selectValues.push(item);
}
});
$(eid).append("</optgroup>");
}else{//不分组
isgroup = false;//分组标识
var status = "";var topborder ="",buttomborder="",checkoff="";
if(option[i].status && option[i].status == '0'){status = "disabled='disabled'";}//是否有效
$(eid).append("<option value='"+option[i].code+"' "+status+">"+option[i].codeName+"</option>");
//内部数据option中的选中标识优先级高于外部指定的优先级
if(option[i].select != undefined && (option[i].select == 'true' || option[i].select == true) && option[i].status != '0'){
that.selectValues.push(option[i]);
}
}
}
//内部无选中则判断外部是否指定,遵循内部优先级高于外部
if(that.selectValues.length == 0 && param.select != undefined){
var item;
var si = param.select+"";
if(isgroup && si.indexOf("-") > 0){//分组时索引为指定为 group-item
var s = si.split("-");//拆分组
item = option[s[0]].groupChildren[s[1]];
}else{
item = option[si];
}
if(item && item.status != '0'){
that.selectValues.push(item);
}
}//选择指定选中项
//var k = eid.replace('#','');
var multiple = $(eid).attr('multiple');//多选控制,暂时无用
//console.log(eid,that.selectValues);
if(that.selectValues.length>0){//默认选中数据在循环外部,提高渲染效率
that.selectValues.forEach(function(item,index){
$(eid).find("option[value = '"+item.code+"']").attr("selected","selected");
});
}else{
//$(eid).find("option[value = '']").attr("selected","selected");//默认选中请选择
}
//加载成功执行回调函数
if(param.success){
//console.log(k+" call success",option);
param.success(option);
option = null;
}
//监听事件:这里做自己想做的事情
form.render('select');//select是固定写法 不是选择器
form.on('select('+eid.replace('#','')+')', function(data){
if(param.onselect){//点击选择事件
param.onselect(data.value);
}
});
}
}
};
exports('layselect',obj);
});
+368
View File
@@ -0,0 +1,368 @@
/**
* date:2020/02/27
* author:Mr.Chung
* version:2.0
* description:layuimini 主体框架扩展
*/
layui.define(["jquery", "miniMenu", "element", "miniTab", "miniTheme"], function (exports) {
var $ = layui.$,
layer = layui.layer,
miniMenu = layui.miniMenu,
miniTheme = layui.miniTheme,
element = layui.element ,
miniTab = layui.miniTab;
if (!/http(s*):\/\//.test(location.href)) {
var tips = "请先将项目部署至web容器(Apache/Tomcat/Nginx/IIS/等),否则部分数据将无法显示";
return layer.alert(tips);
}
var miniAdmin = {
/**
* 后台框架初始化
* @param options.iniUrl 后台初始化接口地址
* @param options.clearUrl 后台清理缓存接口
* @param options.urlHashLocation URL地址hash定位
* @param options.bgColorDefault 默认皮肤
* @param options.multiModule 是否开启多模块
* @param options.menuChildOpen 是否展开子菜单
* @param options.loadingTime 初始化加载时间
* @param options.pageAnim iframe窗口动画
* @param options.maxTabNum 最大的tab打开数量
*/
render: function (options) {
options.iniUrl = options.iniUrl || null;
options.clearUrl = options.clearUrl || null;
options.urlHashLocation = options.urlHashLocation || false;
options.bgColorDefault = options.bgColorDefault || 0;
options.multiModule = options.multiModule || false;
options.menuChildOpen = options.menuChildOpen || false;
options.loadingTime = options.loadingTime || 0;
options.pageAnim = options.pageAnim || false;
options.maxTabNum = options.maxTabNum || 200;
options.isHideOpenMenu = !options.isHideOpenMenu ? options.isHideOpenMenu : true;
$.getJSON(options.iniUrl, function (data) {
if (data == null) {
miniAdmin.error('暂无菜单信息')
} else {
miniAdmin.renderLogo(data.logoInfo);
miniAdmin.renderClear(options.clearUrl);
miniAdmin.renderHome(data.homeInfo);
miniAdmin.renderAnim(options.pageAnim);
miniAdmin.listen();
miniMenu.render({
menuList: data.menuInfo,
multiModule: options.multiModule,
menuChildOpen: options.menuChildOpen
});
miniTab.render({
filter: 'layuiminiTab',
urlHashLocation: options.urlHashLocation,
multiModule: options.multiModule,
menuChildOpen: options.menuChildOpen,
maxTabNum: options.maxTabNum,
menuList: data.menuInfo,
homeInfo: data.homeInfo,
listenSwichCallback: function () {
miniAdmin.renderDevice();
}
});
miniTheme.render({
bgColorDefault: options.bgColorDefault,
listen: true,
});
miniAdmin.deleteLoader(options.loadingTime);
miniAdmin.isHideOpenMenu(options.isHideOpenMenu);
}
}).fail(function () {
miniAdmin.error('菜单接口有误');
});
},
/**
* 点击左侧下拉菜单,关闭其他下拉菜单
* @param data
*/
isHideOpenMenu: function (data) {
$(".layui-side").on("click", ".layui-nav-item", function () {
if (data) {
$(this).siblings('li').attr('class', 'layui-nav-item');
}
});
},
/**
* 初始化logo
* @param data
*/
renderLogo: function (data) {
var html = '<a href="' + data.href + '"><img src="' + data.image + '" style="width:95%;" alt="logo"><h1>' + data.title + '</h1></a>';
$('.layuimini-logo').html(html);
},
/**
* 初始化首页
* @param data
*/
renderHome: function (data) {
sessionStorage.setItem('layuiminiHomeHref', data.href);
$('#layuiminiHomeTabId').html('<span class="layuimini-tab-active"></span><span class="disable-close">' + data.title + '</span><i class="layui-icon layui-unselect layui-tab-close">ဆ</i>');
$('#layuiminiHomeTabId').attr('lay-id', data.href);
$('#layuiminiHomeTabIframe').html('<iframe width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" src="' + data.href + '"></iframe>');
},
/**
* 初始化缓存地址
* @param clearUrl
*/
renderClear: function (clearUrl) {
$('.layuimini-clear').attr('data-href',clearUrl);
},
/**
* 初始化iframe窗口动画
* @param anim
*/
renderAnim: function (anim) {
if (anim) {
$('#layuimini-bg-color').after('<style id="layuimini-page-anim">' +
'.layui-tab-item.layui-show {animation:moveTop 1s;-webkit-animation:moveTop 1s;animation-fill-mode:both;-webkit-animation-fill-mode:both;position:relative;height:100%;-webkit-overflow-scrolling:touch;}\n' +
'@keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}\n' +
'@-o-keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}\n' +
'@-moz-keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}\n' +
'@-webkit-keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}' +
'</style>');
}
},
fullScreen: function () {
var el = document.documentElement;
var rfs = el.requestFullScreen || el.webkitRequestFullScreen;
if (typeof rfs != "undefined" && rfs) {
rfs.call(el);
} else if (typeof window.ActiveXObject != "undefined") {
var wscript = new ActiveXObject("WScript.Shell");
if (wscript != null) {
wscript.SendKeys("{F11}");
}
} else if (el.msRequestFullscreen) {
el.msRequestFullscreen();
} else if (el.oRequestFullscreen) {
el.oRequestFullscreen();
} else if (el.webkitRequestFullscreen) {
el.webkitRequestFullscreen();
} else if (el.mozRequestFullScreen) {
el.mozRequestFullScreen();
} else {
miniAdmin.error('浏览器不支持全屏调用!');
}
},
/**
* 退出全屏
*/
exitFullScreen: function () {
var el = document;
var cfs = el.cancelFullScreen || el.webkitCancelFullScreen || el.exitFullScreen;
if (typeof cfs != "undefined" && cfs) {
cfs.call(el);
} else if (typeof window.ActiveXObject != "undefined") {
var wscript = new ActiveXObject("WScript.Shell");
if (wscript != null) {
wscript.SendKeys("{F11}");
}
} else if (el.msExitFullscreen) {
el.msExitFullscreen();
} else if (el.oRequestFullscreen) {
el.oCancelFullScreen();
}else if (el.mozCancelFullScreen) {
el.mozCancelFullScreen();
} else if (el.webkitCancelFullScreen) {
el.webkitCancelFullScreen();
} else {
miniAdmin.error('浏览器不支持全屏调用!');
}
},
/**
* 初始化设备端
*/
renderDevice: function () {
if (miniAdmin.checkMobile()) {
$('.layuimini-tool i').attr('data-side-fold', 1);
$('.layuimini-tool i').attr('class', 'layui-icon layui-icon-list');
$('.layui-layout-body').removeClass('layuimini-mini');
$('.layui-layout-body').addClass('layuimini-all');
}
},
/**
* 初始化加载时间
* @param loadingTime
*/
deleteLoader: function (loadingTime) {
if (loadingTime) {
setTimeout(function () {
$('.layuimini-loader').fadeOut();
}, loadingTime * 1000)
} else {
$('.layuimini-loader').fadeOut();
}
},
/**
* 成功
* @param title
* @returns {*}
*/
success: function (title) {
return layer.msg(title, {icon: 1, shade: this.shade, scrollbar: false, time: 2000, shadeClose: true});
},
/**
* 失败
* @param title
* @returns {*}
*/
error: function (title) {
return layer.msg(title, {icon: 2, shade: this.shade, scrollbar: false, time: 3000, shadeClose: true});
},
/**
* 判断是否为手机
* @returns {boolean}
*/
checkMobile: function () {
var ua = navigator.userAgent.toLocaleLowerCase();
var pf = navigator.platform.toLocaleLowerCase();
var isAndroid = (/android/i).test(ua) || ((/iPhone|iPod|iPad/i).test(ua) && (/linux/i).test(pf))
|| (/ucweb.*linux/i.test(ua));
var isIOS = (/iPhone|iPod|iPad/i).test(ua) && !isAndroid;
var isWinPhone = (/Windows Phone|ZuneWP7/i).test(ua);
var clientWidth = document.documentElement.clientWidth;
if (!isAndroid && !isIOS && !isWinPhone && clientWidth > 1024) {
return false;
} else {
return true;
}
},
/**
* 监听
*/
listen: function () {
/**
* 清理
*/
$('body').on('click', '[data-clear]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
sessionStorage.clear();
// 判断是否清理服务端
var clearUrl = $(this).attr('data-href');
if (clearUrl != undefined && clearUrl != '' && clearUrl != null) {
$.getJSON(clearUrl, function (data, status) {
layer.close(loading);
if (data.code != 0) {
return miniAdmin.error(data.msg);
} else {
return miniAdmin.success(data.msg);
}
}).fail(function () {
layer.close(loading);
return miniAdmin.error('清理缓存接口有误');
});
} else {
layer.close(loading);
return miniAdmin.success('清除缓存成功');
}
});
/**
* 刷新
*/
$('body').on('click', '[data-refresh]', function () {
$(".layui-tab-item.layui-show").find("iframe")[0].contentWindow.location.reload();
miniAdmin.success('刷新成功');
});
/**
* 监听提示信息
*/
$("body").on("mouseenter", ".layui-nav-tree .menu-li", function () {
if (miniAdmin.checkMobile()) {
return false;
}
var classInfo = $(this).attr('class'),
tips = $(this).prop("innerHTML"),
isShow = $('.layuimini-tool i').attr('data-side-fold');
if (isShow == 0 && tips) {
tips = "<ul class='layuimini-menu-left-zoom layui-nav layui-nav-tree layui-this'><li class='layui-nav-item layui-nav-itemed'>"+tips+"</li></ul>" ;
window.openTips = layer.tips(tips, $(this), {
tips: [2, '#2f4056'],
time: 300000,
skin:"popup-tips",
success:function (el) {
var left = $(el).position().left - 10 ;
$(el).css({ left:left });
element.render();
}
});
}
});
$("body").on("mouseleave", ".popup-tips", function () {
if (miniAdmin.checkMobile()) {
return false;
}
var isShow = $('.layuimini-tool i').attr('data-side-fold');
if (isShow == 0) {
try {
layer.close(window.openTips);
} catch (e) {
console.log(e.message);
}
}
});
/**
* 全屏
*/
$('body').on('click', '[data-check-screen]', function () {
var check = $(this).attr('data-check-screen');
if (check == 'full') {
miniAdmin.fullScreen();
$(this).attr('data-check-screen', 'exit');
$(this).html('<i class="layui-icon layui-icon-screen-restore"></i>');
} else {
miniAdmin.exitFullScreen();
$(this).attr('data-check-screen', 'full');
$(this).html('<i class="layui-icon layui-icon-screen-full"></i>');
}
});
/**
* 点击遮罩层
*/
$('body').on('click', '.layuimini-make', function () {
miniAdmin.renderDevice();
});
}
};
exports("miniAdmin", miniAdmin);
});
+253
View File
@@ -0,0 +1,253 @@
/**
* date:2020/02/27
* author:Mr.Chung
* version:2.0
* description:layuimini 菜单框架扩展
*/
layui.define(["element","laytpl" ,"jquery"], function (exports) {
var element = layui.element,
$ = layui.$,
laytpl = layui.laytpl,
layer = layui.layer;
var miniMenu = {
/**
* 菜单初始化
* @param options.menuList 菜单数据信息
* @param options.multiModule 是否开启多模块
* @param options.menuChildOpen 是否展开子菜单
*/
render: function (options) {
options.menuList = options.menuList || [];
options.multiModule = options.multiModule || false;
options.menuChildOpen = options.menuChildOpen || false;
if (options.multiModule) {
miniMenu.renderMultiModule(options.menuList, options.menuChildOpen);
} else {
miniMenu.renderSingleModule(options.menuList, options.menuChildOpen);
}
miniMenu.listen();
},
/**
* 单模块
* @param menuList 菜单数据
* @param menuChildOpen 是否默认展开
*/
renderSingleModule: function (menuList, menuChildOpen) {
menuList = menuList || [];
var leftMenuHtml = '',
childOpenClass = '',
leftMenuCheckDefault = 'layui-this';
var me = this ;
if (menuChildOpen) childOpenClass = ' layui-nav-itemed';
leftMenuHtml = this.renderLeftMenu(menuList,{ childOpenClass:childOpenClass }) ;
$('.layui-layout-body').addClass('layuimini-single-module'); //单模块标识
$('.layuimini-header-menu').remove();
$('.layuimini-menu-left').html(leftMenuHtml);
element.init();
},
/**
* 渲染一级菜单
*/
compileMenu: function(menu,isSub){
var menuHtml = '<li {{#if( d.menu){ }} data-menu="{{d.menu}}" {{#}}} class="layui-nav-item menu-li {{d.childOpenClass}} {{d.className}}" {{#if( d.id){ }} id="{{d.id}}" {{#}}}> <a href="javascript:;" {{#if( d.menu){ }} data-menu="{{d.menu}}" {{#}}} {{#if( d.dizhi){ }} layuimini-href="{{d.dizhi}}" {{#}}} {{#if( d.target){ }} target="{{d.target}}" {{#}}}>{{#if( d.icon){ }} <i class="layui-icon layui-icon-{{d.icon}}"></i> {{#}}} <span class="layui-left-nav {{-d.title}}">{{-d.title}}</span></a> {{# if(d.children){}} {{-d.children}} {{#}}} </li>' ;
if(isSub){
menuHtml = '<dd class="menu-dd {{d.childOpenClass}} {{ d.className }}"> <a href="javascript:;" {{#if( d.menu){ }} data-menu="{{d.menu}}" {{#}}} {{#if( d.id){ }} id="{{d.id}}" {{#}}} {{#if(( !d.children || !d.children.length ) && d.dizhi){ }} layuimini-href="{{d.dizhi}}" {{#}}} {{#if( d.target){ }} target="{{d.target}}" {{#}}}> {{#if( d.icon){ }} <i class="layui-icon layui-icon-{{d.icon}}"></i> {{#}}} <span class="layui-left-nav {{-d.title}}"> {{-d.title}}</span></a> {{# if(d.children){}} {{-d.children}} {{#}}}</dd>'
}
return laytpl(menuHtml).render(menu);
},
compileMenuContainer :function(menu,isSub){
var wrapperHtml = '<ul class="layui-nav layui-nav-tree layui-left-nav-tree {{d.className}}" id="{{d.id}}">{{-d.children}}</ul>' ;
if(isSub){
wrapperHtml = '<dl class="layui-nav-child">{{-d.children}}</dl>' ;
}
if(!menu.children){
return "";
}
return laytpl(wrapperHtml).render(menu);
},
each:function(list,callback){
var _list = [];
for(var i = 0 ,length = list.length ; i<length ;i++ ){
_list[i] = callback(i,list[i]) ;
}
return _list ;
},
renderChildrenMenu:function(menuList,options){
var me = this ;
menuList = menuList || [] ;
// console.log("menuList",menuList);
var html = this.each(menuList,function (idx,menu) {
if(menu.children && menu.children.length){
menu.children = me.renderChildrenMenu(menu.children,{ childOpenClass: options.childOpenClass || '' });
}
menu.className = "" ;
menu.childOpenClass = options.childOpenClass || ''
return me.compileMenu(menu,true)
}).join("");
return me.compileMenuContainer({ children:html },true)
},
renderLeftMenu :function(leftMenus,options){
options = options || {};
var me = this ;
var leftMenusHtml = me.each(leftMenus || [],function (idx,leftMenu) { // 左侧菜单遍历
var children = me.renderChildrenMenu(leftMenu.children, { childOpenClass:options.childOpenClass });
var leftMenuHtml = me.compileMenu({
href: leftMenu.href,
dizhi: leftMenu.dizhi,
id:leftMenu.id,
target: leftMenu.target,
childOpenClass: options.childOpenClass,
icon: leftMenu.icon,
title: leftMenu.title,
children: children,
className: '',
});
return leftMenuHtml ;
}).join("");
leftMenusHtml = me.compileMenuContainer({ id:options.parentMenuId,className:options.leftMenuCheckDefault,children:leftMenusHtml }) ;
return leftMenusHtml ;
},
/**
* 多模块
* @param menuList 菜单数据
* @param menuChildOpen 是否默认展开
*/
renderMultiModule: function (menuList, menuChildOpen) {
menuList = menuList || [];
var me = this ;
var headerMenuHtml = '',
headerMobileMenuHtml = '',
leftMenuHtml = '',
leftMenuCheckDefault = 'layui-this',
childOpenClass = '',
headerMenuCheckDefault = 'layui-this';
if (menuChildOpen) childOpenClass = ' layui-nav-itemed';
var headerMenuHtml = this.each(menuList, function (index, val) { //顶部菜单渲染
var menu = 'multi_module_' + index ;
var id = menu+"HeaderId";
var topMenuItemHtml = "" ;
topMenuItemHtml = me.compileMenu({
className:headerMenuCheckDefault,
menu:menu,
id:id,
title:val.title,
href:"",
target:"",
children:""
});
leftMenuHtml+=me.renderLeftMenu(val.children,{
parentMenuId:menu,
childOpenClass:childOpenClass,
leftMenuCheckDefault:leftMenuCheckDefault
});
headerMobileMenuHtml +=me.compileMenu({ id:id,menu:menu,id:id,icon:val.icon, title:val.title, },true);
headerMenuCheckDefault = "";
leftMenuCheckDefault = "layui-hide" ;
return topMenuItemHtml ;
}).join("");
$('.layui-layout-body').addClass('layuimini-multi-module'); //多模块标识
$('.layuimini-menu-header-pc').html(headerMenuHtml); //电脑
$('.layuimini-menu-left').html(leftMenuHtml);
$('.layuimini-menu-header-mobile').html(headerMobileMenuHtml); //手机
element.init();
},
/**
* 监听
*/
listen: function () {
/**
* 菜单模块切换
*/
$('body').on('click', '[data-menu]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var menuId = $(this).attr('data-menu');
// header
$(".layuimini-header-menu .layui-nav-item.layui-this").removeClass('layui-this');
$(this).addClass('layui-this');
// left
$(".layuimini-menu-left .layui-nav.layui-nav-tree.layui-this").addClass('layui-hide');
$(".layuimini-menu-left .layui-nav.layui-nav-tree.layui-this.layui-hide").removeClass('layui-this');
$("#" + menuId).removeClass('layui-hide');
$("#" + menuId).addClass('layui-this');
layer.close(loading);
});
/**
* 菜单缩放
*/
$('body').on('click', '.layuimini-site-mobile', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var isShow = $('.layuimini-tool [data-side-fold]').attr('data-side-fold');
if (isShow == 1) { // 缩放
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 0);
$('.layuimini-tool [data-side-fold]').attr('class', 'layui-icon layui-icon-spread-left');
$('.layui-layout-body').removeClass('layuimini-all');
$('.layui-layout-body').addClass('layuimini-mini');
} else { // 正常
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 1);
$('.layuimini-tool [data-side-fold]').attr('class', 'layui-icon layui-icon-shrink-right');
$('.layui-layout-body').removeClass('layuimini-mini');
$('.layui-layout-body').addClass('layuimini-all');
layer.close(window.openTips);
}
element.init();
layer.close(loading);
});
/**
* 菜单缩放
*/
$('body').on('click', '[data-side-fold]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var isShow = $('.layuimini-tool [data-side-fold]').attr('data-side-fold');
if (isShow == 1) { // 缩放
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 0);
$('.layuimini-tool [data-side-fold]').attr('class', 'layui-icon layui-icon-spread-left');
$('.layui-layout-body').removeClass('layuimini-all');
$('.layui-layout-body').addClass('layuimini-mini');
// $(".menu-li").each(function (idx,el) {
// $(el).addClass("hidden-sub-menu");
// });
} else { // 正常
$('.layuimini-tool [data-side-fold]').attr('data-side-fold', 1);
$('.layuimini-tool [data-side-fold]').attr('class', 'layui-icon layui-icon-shrink-right');
$('.layui-layout-body').removeClass('layuimini-mini');
$('.layui-layout-body').addClass('layuimini-all');
// $(".menu-li").each(function (idx,el) {
// $(el).removeClass("hidden-sub-menu");
// });
layer.close(window.openTips);
}
element.init();
layer.close(loading);
});
/**
* 手机端点开模块
*/
$('body').on('click', '.layuimini-header-menu.layuimini-mobile-show dd', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var check = $('.layuimini-tool [data-side-fold]').attr('data-side-fold');
if(check === "1"){
$('.layuimini-site-mobile').trigger("click");
element.init();
}
layer.close(loading);
});
},
};
exports("miniMenu", miniMenu);
});
+676
View File
@@ -0,0 +1,676 @@
/**
* date:2020/02/27
* author:Mr.Chung
* version:2.0
* description:layuimini tab框架扩展
* 新增功能: 点击左侧菜单,如果标签存在则刷新,不存在则新建
* 修改bug: 打开多个标签时,点击关闭当前标签时会把当前标签及后面的标签全部关闭的bug,364行
*/
layui.define(["element", "layer", "jquery","tabs"], function (exports) {
var element = layui.element,
tabs=layui.tabs,
layer = layui.layer,
$ = layui.$;
var miniTab = {
/**
* 初始化tab
* @param options
*/
render: function (options) {
options.filter = options.filter || null;
options.multiModule = options.multiModule || false;
options.urlHashLocation = options.urlHashLocation || false;
options.maxTabNum = options.maxTabNum || 200;
options.menuList = options.menuList || []; // todo 后期菜单想改为不操作dom, 而是直接操作初始化传过来的数据
options.homeInfo = options.homeInfo || {};
options.listenSwichCallback = options.listenSwichCallback || function () {
};
miniTab.listen(options);
miniTab.listenRoll();
miniTab.listenSwitch(options);
miniTab.listenHash(options);
},
/**
* 新建tab窗口
* @param options.tabId
* @param options.href
* @param options.title
* @param options.isIframe
* @param options.maxTabNum
*/
create: function (options) {
options.href = options.href || null;
options.tabId = options.tabId || options.href;
options.title = options.title || null;
options.isIframe = options.isIframe || false;
options.maxTabNum = options.maxTabNum || 200;
if ($(".layuimini-tab .layui-tab-title li").length >= options.maxTabNum) {
layer.msg('Tab窗口已达到限定数量,请先关闭部分Tab');
return false;
}
var ele = element;
if (options.isIframe) ele = parent.layui.element;
//
console.log('aaa');
ele.tabAdd('layuiminiTab', {
title: '<span class="layuimini-tab-active"></span><span>' + options.title + '</span><i class="layui-icon layui-unselect layui-tab-close">ဆ</i>' //用于演示
, content: '<iframe width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" id="'+options.tabId+'" src="' + options.href + '"></iframe>'
, id: options.tabId
});
console.log('bbb');
//
$('.layuimini-menu-left').attr('layuimini-tab-tag', 'add');
sessionStorage.setItem('layuiminimenu_' + options.tabId, options.title);
},
/**
* 切换选项卡
* @param tabId
*/
change: function (tabId) {
element.tabChange('layuiminiTab', tabId);
},
/**
* 删除tab窗口
* @param tabId
* @param isParent
*/
delete: function (tabId, isParent) {
// todo 未知BUG,不知道是不是layui问题,必须先删除元素
$(".layuimini-tab .layui-tab-title .layui-unselect.layui-tab-bar").remove();
if (isParent === true) {
parent.layui.element.tabDelete('layuiminiTab', tabId);
} else {
element.tabDelete('layuiminiTab', tabId);
}
},
/**
* 在iframe层打开新tab方法
*/
openNewTabByIframe: function (options) {
options.href = options.href || null;
options.id = options.id || options.href;
options.title = options.title || null;
var loading = parent.layer.load(0, {shade: false, time: 2 * 1000});
if (options.href === null || options.href === undefined) options.href = new Date().getTime();
var checkTab = miniTab.check(options.id, true);
if (!checkTab) {
parent.layui.element.tabChange('layuiminiTab','0');
setTimeout(function(){
miniTab.create({
tabId: options.id,
href: options.href,
title: options.title,
isIframe: true,
});
parent.layui.element.tabChange('layuiminiTab', options.id);
parent.layer.close(loading);
},100);
}else{
parent.layui.element.tabChange('layuiminiTab', options.id);
parent.layer.close(loading);
}
},
openNewTab: function (options) {
// console.log(options,'o');
options.href = options.href || null;
options.id = options.id || options.href;
options.title = options.title || null;
// console.log(options,'p');
var loading = layer.load(0, {shade: false, time: 2 * 1000});
if (options.href === null || options.href === undefined) options.href = new Date().getTime();
var checkTab = miniTab.check(options.id, true);
// console.log(checkTab,'po',options.id);
if (!checkTab) {
layui.element.tabChange('layuiminiTab','0');
setTimeout(() => {
miniTab.create({
tabId: options.id,
href: options.href,
title: options.title,
isIframe: true,
});
layui.element.tabChange('layuiminiTab', options.id);
layer.close(loading);
}, 100);
}else{
layui.element.tabChange('layuiminiTab', options.id);
layer.close(loading);
}
},
/**
* 在iframe层关闭当前tab方法
*/
deleteCurrentByIframe: function () {
var ele = $(".layuimini-tab .layui-tab-title li.layui-this", parent.document);
if (ele.length > 0) {
var layId = $(ele[0]).attr('lay-id');
miniTab.delete(layId, true);
}
},
/**
* 判断tab窗口
*/
check: function (tabId, isIframe) {
// 判断选项卡上是否有
tabId=tabId+"";
var checkTab = false;
if (isIframe === undefined || isIframe === false) {
$(".layui-tab-title li").each(function () {
var checkTabId = $(this).attr('lay-id');
if (checkTabId != null && checkTabId === tabId) {
checkTab = true;
}
});
} else {
parent.layui.$(".layui-tab-title li").each(function () {
var checkTabId = $(this).attr('lay-id');
if (checkTabId != null && checkTabId === tabId) {
checkTab = true;
}
});
}
return checkTab;
},
/**
* 开启tab右键菜单
* @param tabId
* @param left
*/
openTabRignMenu: function (tabId, left) {
miniTab.closeTabRignMenu();
var menuHtml = '<div class="layui-unselect layui-form-select layui-form-selected layuimini-tab-mousedown layui-show" data-tab-id="' + tabId + '" style="left: ' + left + 'px!important">\n' +
'<dl>\n' +
'<dd><a href="javascript:;" layuimini-tab-menu-close="current">关 闭 当 前</a></dd>\n' +
'<dd><a href="javascript:;" layuimini-tab-menu-close="other">关 闭 其 他</a></dd>\n' +
'<dd><a href="javascript:;" layuimini-tab-menu-close="all">关 闭 全 部</a></dd>\n' +
'<dd><a href="javascript:;" layuimini-tab-menu-close="divorced">脱 离 标 签</a></dd>\n' +
'</dl>\n' +
'</div>';
var makeHtml = '<div class="layuimini-tab-make"></div>';
$('.layuimini-tab .layui-tab-title').after(menuHtml);
$('.layuimini-tab .layui-tab-content').after(makeHtml);
},
/**
* 关闭tab右键菜单
*/
closeTabRignMenu: function () {
$('.layuimini-tab-mousedown').remove();
$('.layuimini-tab-make').remove();
},
/**
* 查询菜单信息
* @param href
* @param menuList
*/
searchMenu: function (href, menuList) {
var menu;
for (key in menuList) {
var item = menuList[key];
if (item.href === href) {
menu = item;
break;
}
if (item.child) {
newMenu = miniTab.searchMenu(href, item.child);
if (newMenu) {
menu = newMenu;
break;
}
}
}
return menu;
},
/**
* 监听
* @param options
*/
listen: function (options) {
options = options || {};
options.maxTabNum = options.maxTabNum || 200;
/**
* 打开新窗口
*/
$('body').on('click', '[layuimini-href]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var tabId = $(this).attr('layuimini-href'),
href = $(this).attr('layuimini-href'),
title = $(this).text(),
target = $(this).attr('target');
var el = $("[layuimini-href='" + href + "']", ".layuimini-menu-left");
layer.close(window.openTips);
if (el.length) {
$(el).closest(".layui-nav-tree").find(".layui-this").removeClass("layui-this");
$(el).parent().addClass("layui-this");
}
if (target === '_blank') {
layer.close(loading);
window.open(href, "_blank");
return false;
}
if (tabId === null || tabId === undefined) tabId = new Date().getTime();
var checkTab = miniTab.check(tabId);
if(checkTab){
miniTab.change(tabId);
}
if (!checkTab) {
miniTab.create({
tabId: tabId,
href: href,
title: title,
isIframe: false,
maxTabNum: options.maxTabNum,
});
}
element.tabChange('layuiminiTab', tabId);
layer.close(loading);
});
/**
* 在iframe子菜单上打开新窗口
*/
$('body').on('click', '[layuimini-content-href]', function () {
var loading = parent.layer.load(0, {shade: false, time: 2 * 1000});
var tabId = $(this).attr('layuimini-content-href'),
href = $(this).attr('layuimini-content-href'),
title = $(this).attr('data-title'),
target = $(this).attr('target');
if (target === '_blank') {
parent.layer.close(loading);
window.open(href, "_blank");
return false;
}
if (tabId === null || tabId === undefined) tabId = new Date().getTime();
var checkTab = miniTab.check(tabId, true);
if (!checkTab) {
miniTab.create({
tabId: tabId,
href: href,
title: title,
isIframe: true,
maxTabNum: options.maxTabNum,
});
}
parent.layui.element.tabChange('layuiminiTab', tabId);
parent.layer.close(loading);
});
/**
* 关闭选项卡
**/
$('body').on('click', '.layuimini-tab .layui-tab-title .layui-tab-close', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var $parent = $(this).parent();
var tabId = $parent.attr('lay-id');
if (tabId !== undefined || tabId !== null) {
miniTab.delete(tabId);
}
layer.close(loading);
});
/**
* 选项卡操作
*/
$('body').on('click', '[layuimini-tab-close]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var closeType = $(this).attr('layuimini-tab-close');
$(".layuimini-tab .layui-tab-title li").each(function () {
var tabId = $(this).attr('lay-id');
var id = $(this).attr('id');
var isCurrent = $(this).hasClass('layui-this');
if (id !== 'layuiminiHomeTabId') {
if (closeType === 'all') {
miniTab.delete(tabId);
} else {
if (closeType === 'current' && isCurrent) {
miniTab.delete(tabId);
} else if (closeType === 'other' && !isCurrent) {
miniTab.delete(tabId);
}
}
}
});
layer.close(loading);
});
/**
* 禁用网页右键
*/
$(".layuimini-tab .layui-tab-title").unbind("mousedown").bind("contextmenu", function (e) {
e.preventDefault();
return false;
});
/**
* 注册鼠标右键
*/
$('body').on('mousedown', '.layuimini-tab .layui-tab-title li', function (e) {
var left = $(this).offset().left - $('.layuimini-tab ').offset().left + ($(this).width() / 2),
tabId = $(this).attr('lay-id');
if (e.which === 3) {
miniTab.openTabRignMenu(tabId, left);
}
});
/**
* 关闭tab右键菜单
*/
$('body').on('click', '.layui-body,.layui-header,.layuimini-menu-left,.layuimini-tab-make', function () {
miniTab.closeTabRignMenu();
});
/**
* tab右键选项卡操作
*/
$('body').on('click', '[layuimini-tab-menu-close]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var closeType = $(this).attr('layuimini-tab-menu-close'),
currentTabId = $('.layuimini-tab-mousedown').attr('data-tab-id');
$(".layuimini-tab .layui-tab-title li").each(function () {
var tabId = $(this).attr('lay-id');
var id = $(this).attr('id');
if (id !== 'layuiminiHomeTabId') {
if (closeType === 'all') {
miniTab.delete(tabId);
} else {
if (closeType === 'current' && currentTabId === tabId) {
miniTab.delete(tabId);
return false;
} else if (closeType === 'other' && currentTabId !== tabId) {
miniTab.delete(tabId);
} else if (closeType === 'divorced' && currentTabId === tabId) {
miniTab.divorced(tabId);
}
}
}
});
miniTab.closeTabRignMenu();
layer.close(loading);
});
},
/**
* 监听tab切换
* @param options
*/
listenSwitch: function (options) {
options.filter = options.filter || null;
options.multiModule = options.multiModule || false;
options.urlHashLocation = options.urlHashLocation || false;
options.listenSwichCallback = options.listenSwichCallback || function () {
};
element.on('tab(' + options.filter + ')', function (data) {
var tabId = $(this).attr('lay-id');
if (options.urlHashLocation) {
location.hash = '/' + tabId;
}
if (typeof options.listenSwichCallback === 'function') {
options.listenSwichCallback();
}
if (typeof options.switchtoindex === 'function') {
options.switchtoindex();
}
// 判断是否为新增窗口
if ($('.layuimini-menu-left').attr('layuimini-tab-tag') === 'add') {
$('.layuimini-menu-left').attr('layuimini-tab-tag', 'no')
}
$("div.layui-side ul li.layui-nav-itemed").removeClass("layui-nav-itemed");
$("[layuimini-href]").parent().removeClass('layui-this');
if (options.multiModule) {
miniTab.listenSwitchMultiModule(tabId);
} else {
miniTab.listenSwitchSingleModule(tabId);
}
miniTab.rollPosition();
});
},
/**
* 监听hash变化
* @param options
* @returns {boolean}
*/
listenHash: function (options) {
options.urlHashLocation = options.urlHashLocation || false;
options.maxTabNum = options.maxTabNum || 200;
options.homeInfo = options.homeInfo || {};
options.menuList = options.menuList || [];
if (!options.urlHashLocation) return false;
var tabId = location.hash.replace(/^#\//, '');
if (tabId === null || tabId === undefined || tabId ==='') return false;
// 判断是否为首页
if(tabId ===options.homeInfo.href) return false;
// 判断是否为右侧菜单
var menu = miniTab.searchMenu(tabId, options.menuList);
if (menu !== undefined) {
miniTab.create({
tabId: tabId,
href: tabId,
title: menu.title,
isIframe: false,
maxTabNum: options.maxTabNum,
});
$('.layuimini-menu-left').attr('layuimini-tab-tag', 'no');
element.tabChange('layuiminiTab', tabId);
return false;
}
// 判断是否为快捷菜单
var isSearchMenu = false;
$("[layuimini-content-href]").each(function () {
if ($(this).attr("layuimini-content-href") === tabId) {
var title = $(this).attr("data-title");
miniTab.create({
tabId: tabId,
href: tabId,
title: title,
isIframe: false,
maxTabNum: options.maxTabNum,
});
$('.layuimini-menu-left').attr('layuimini-tab-tag', 'no');
element.tabChange('layuiminiTab', tabId);
isSearchMenu = true;
return false;
}
});
if (isSearchMenu) return false;
// 既不是右侧菜单、快捷菜单,就直接打开
var title = sessionStorage.getItem('layuiminimenu_' + tabId) === null ? tabId : sessionStorage.getItem('layuiminimenu_' + tabId);
miniTab.create({
tabId: tabId,
href: tabId,
title: title,
isIframe: false,
maxTabNum: options.maxTabNum,
});
element.tabChange('layuiminiTab', tabId);
return false;
},
/**
* 监听滚动
*/
listenRoll: function () {
$(".layuimini-tab-roll-left").click(function () {
miniTab.rollClick("left");
});
$(".layuimini-tab-roll-right").click(function () {
miniTab.rollClick("right");
});
},
/**
* 单模块切换
* @param tabId
*/
listenSwitchSingleModule: function (tabId) {
$("[layuimini-href]").each(function () {
if ($(this).attr("layuimini-href") === tabId) {
// 自动展开菜单栏
var addMenuClass = function ($element, type) {
if (type === 1) {
$element.addClass('layui-this');
if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-this')) {
$(".layuimini-header-menu li").attr('class', 'layui-nav-item');
} else {
addMenuClass($element.parent().parent(), 2);
}
} else {
$element.addClass('layui-nav-itemed');
if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-nav-itemed')) {
$(".layuimini-header-menu li").attr('class', 'layui-nav-item');
} else {
addMenuClass($element.parent().parent(), 2);
}
}
};
addMenuClass($(this).parent(), 1);
return false;
}
});
},
/**
* 多模块切换
* @param tabId
*/
listenSwitchMultiModule: function (tabId) {
$("[layuimini-href]").each(function () {
if ($(this).attr("layuimini-href") === tabId) {
// 自动展开菜单栏
var addMenuClass = function ($element, type) {
if (type === 1) {
$element.addClass('layui-this');
if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-this')) {
var moduleId = $element.parent().attr('id');
$(".layuimini-header-menu li").attr('class', 'layui-nav-item');
$("#" + moduleId + "HeaderId").addClass("layui-this");
$(".layuimini-menu-left .layui-nav.layui-nav-tree").attr('class', 'layui-nav layui-nav-tree layui-hide');
$("#" + moduleId).attr('class', 'layui-nav layui-nav-tree layui-this');
} else {
addMenuClass($element.parent().parent(), 2);
}
} else {
$element.addClass('layui-nav-itemed');
if ($element.hasClass('layui-nav-item') && $element.hasClass('layui-nav-itemed')) {
var moduleId = $element.parent().attr('id');
$(".layuimini-header-menu li").attr('class', 'layui-nav-item');
$("#" + moduleId + "HeaderId").addClass("layui-this");
$(".layuimini-menu-left .layui-nav.layui-nav-tree").attr('class', 'layui-nav layui-nav-tree layui-hide');
$("#" + moduleId).attr('class', 'layui-nav layui-nav-tree layui-this');
} else {
addMenuClass($element.parent().parent(), 2);
}
}
};
addMenuClass($(this).parent(), 1);
return false;
}
});
},
/**
* 自动定位
*/
rollPosition: function () {
var $tabTitle = $('.layuimini-tab .layui-tab-title');
var autoLeft = 0;
$tabTitle.children("li").each(function () {
if ($(this).hasClass('layui-this')) {
return false;
} else {
autoLeft += $(this).outerWidth();
}
});
$tabTitle.animate({
scrollLeft: autoLeft - $tabTitle.width() / 3
}, 200);
},
/**
* 点击滚动
* @param direction
*/
rollClick: function (direction) {
var $tabTitle = $('.layuimini-tab .layui-tab-title');
var left = $tabTitle.scrollLeft();
if ('left' === direction) {
$tabTitle.animate({
scrollLeft: left - 450
}, 200);
} else {
$tabTitle.animate({
scrollLeft: left + 450
}, 200);
}
},
/**
* 脱离标签栏
* @param tabId
*/
divorced: function (tabId) {
let tabtitle = $("ul.layui-tab-title").children('li[lay-id="' + tabId + '"]');
let title = tabtitle.children("span").text();
let tab = $("div.layui-tab-item").children("iframe[id='" + tabId + "']");
let id = tabId.replace(/[^\u4e00-\u9fa5\w]/g, "");
layer.open({
id: id,
title: title,
type: 1,
content: "",
shadeClose: false,
shade: 0,
maxmin: true,
area: ['50%', '80%'],
success: function (layero, index) {
//layero tab
tabtitle.hide();
tabtitle.removeClass("layui-this");
tab.parent("div.layui-tab-item").attr("layui-id", index);
tab.appendTo($(layero).children("div#" + id));
//$(layero).children("div#" + id)[0].addendChild(tab[0]);
},
cancel: function (index, layero) {
let iframe = $(layero).children("div#" + id).children("iframe");
iframe.appendTo($("div.layui-tab-item[layui-id=" + index + "]"));
//$("div.layui-tab-item.layui-show")[0].addendChild(iframe[0]);
tabtitle.addClass("layui-this");
tabtitle.show();
},
end: function () {
layer.msg("已关闭");
}
});
}
};
exports("miniTab", miniTab);
});
+469
View File
@@ -0,0 +1,469 @@
/**
* date:2020/02/28
* author:Mr.Chung
* version:2.0
* description:layuimini tab框架扩展
*/
layui.define(["jquery", "layer"], function (exports) {
var $ = layui.$,
layer = layui.layer;
var miniTheme = {
/**
* 主题配置项
* @param bgcolorId
* @returns {{headerLogo, menuLeftHover, headerRight, menuLeft, headerRightThis, menuLeftThis}|*|*[]}
*/
config: function (bgcolorId) {
var bgColorConfig = [
{
headerRightBg: '#ffffff', //头部右侧背景色
headerRightBgThis: '#e4e4e4', //头部右侧选中背景色,
headerRightColor: 'rgba(107, 107, 107, 0.7)', //头部右侧字体颜色,
headerRightChildColor: 'rgba(107, 107, 107, 0.7)', //头部右侧下拉字体颜色,
headerRightColorThis: '#565656', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(160, 160, 160, 0.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#247AE0', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#565656', //头部缩放按钮样式,
headerLogoBg: '#192027', //logo背景颜色,
headerLogoColor: 'rgb(191, 187, 187)', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#28333E', //左侧菜单背景,
leftMenuBgThis: '#247AE0', //左侧菜单选中背景,
leftMenuChildBg: '#0c0f13', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#247AE0', //tab选项卡选中颜色,
},
{
headerRightBg: '#23262e', //头部右侧背景色
headerRightBgThis: '#0c0c0c', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#1aa094', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#0c0c0c', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#23262e', //左侧菜单背景,
leftMenuBgThis: '#737373', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#23262e', //tab选项卡选中颜色,
},
{
headerRightBg: '#ffa4d1', //头部右侧背景色
headerRightBgThis: '#bf7b9d', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#ffa4d1', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#e694bd', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#1f1f1f', //左侧菜单背景,
leftMenuBgThis: '#737373', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#ffa4d1', //tab选项卡选中颜色,
},
{
headerRightBg: '#1aa094', //头部右侧背景色
headerRightBgThis: '#197971', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#1aa094', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#0c0c0c', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#23262e', //左侧菜单背景,
leftMenuBgThis: '#1aa094', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#1aa094', //tab选项卡选中颜色,
},
{
headerRightBg: '#1e9fff', //头部右侧背景色
headerRightBgThis: '#0069b7', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#1e9fff', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#0c0c0c', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#1f1f1f', //左侧菜单背景,
leftMenuBgThis: '#1e9fff', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#1e9fff', //tab选项卡选中颜色,
},
{
headerRightBg: '#ffb800', //头部右侧背景色
headerRightBgThis: '#d09600', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#d09600', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#243346', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#2f4056', //左侧菜单背景,
leftMenuBgThis: '#8593a7', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#ffb800', //tab选项卡选中颜色,
},
{
headerRightBg: '#e82121', //头部右侧背景色
headerRightBgThis: '#ae1919', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#ae1919', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#0c0c0c', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#1f1f1f', //左侧菜单背景,
leftMenuBgThis: '#3b3f4b', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#e82121', //tab选项卡选中颜色,
},
{
headerRightBg: '#963885', //头部右侧背景色
headerRightBgThis: '#772c6a', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#772c6a', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#243346', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#2f4056', //左侧菜单背景,
leftMenuBgThis: '#586473', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#963885', //tab选项卡选中颜色,
},
{
headerRightBg: '#2D8CF0', //头部右侧背景色
headerRightBgThis: '#0069b7', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#0069b7', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#0069b7', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#1f1f1f', //左侧菜单背景,
leftMenuBgThis: '#2D8CF0', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#2d8cf0', //tab选项卡选中颜色,
},
{
headerRightBg: '#ffb800', //头部右侧背景色
headerRightBgThis: '#d09600', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#d09600', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#d09600', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#2f4056', //左侧菜单背景,
leftMenuBgThis: '#3b3f4b', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#ffb800', //tab选项卡选中颜色,
},
{
headerRightBg: '#e82121', //头部右侧背景色
headerRightBgThis: '#ae1919', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#ae1919', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#d91f1f', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#1f1f1f', //左侧菜单背景,
leftMenuBgThis: '#3b3f4b', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#e82121', //tab选项卡选中颜色,
},
{
headerRightBg: '#963885', //头部右侧背景色
headerRightBgThis: '#772c6a', //头部右侧选中背景色,
headerRightColor: 'rgba(255,255,255,.7)', //头部右侧字体颜色,
headerRightChildColor: '#676767', //头部右侧下拉字体颜色,
headerRightColorThis: '#ffffff', //头部右侧鼠标选中,
headerRightNavMore: 'rgba(255,255,255,.7)', //头部右侧更多下拉颜色,
headerRightNavMoreBg: '#772c6a', //头部右侧更多下拉列表选中背景色,
headerRightNavMoreColor: '#ffffff', //头部右侧更多下拉列表字体色,
headerRightToolColor: '#bbe3df', //头部缩放按钮样式,
headerLogoBg: '#772c6a', //logo背景颜色,
headerLogoColor: '#ffffff', //logo字体颜色,
leftMenuNavMore: 'rgb(191, 187, 187)', //左侧菜单更多下拉样式,
leftMenuBg: '#2f4056', //左侧菜单背景,
leftMenuBgThis: '#626f7f', //左侧菜单选中背景,
leftMenuChildBg: 'rgba(0,0,0,.3)', //左侧菜单子菜单背景,
leftMenuColor: 'rgb(191, 187, 187)', //左侧菜单字体颜色,
leftMenuColorThis: '#ffffff', //左侧菜单选中字体颜色,
tabActiveColor: '#963885', //tab选项卡选中颜色,
}
];
if (bgcolorId === undefined) {
return bgColorConfig;
} else {
return bgColorConfig[bgcolorId];
}
},
/**
* 初始化
* @param options
*/
render: function (options) {
options.bgColorDefault = options.bgColorDefault || false;
options.listen = options.listen || false;
var bgcolorId = sessionStorage.getItem('layuiminiBgcolorId');
if (bgcolorId === null || bgcolorId === undefined || bgcolorId === '') {
bgcolorId = options.bgColorDefault;
}
miniTheme.buildThemeCss(bgcolorId);
if (options.listen) miniTheme.listen(options);
},
/**
* 构建主题样式
* @param bgcolorId
* @returns {boolean}
*/
buildThemeCss: function (bgcolorId) {
if (!bgcolorId) {
return false;
}
var bgcolorData = miniTheme.config(bgcolorId);
var styleHtml = '/*头部右侧背景色 headerRightBg */\n' +
'.layui-layout-admin .layui-header {\n' +
' background-color: ' + bgcolorData.headerRightBg + ' !important;\n' +
'}\n' +
'\n' +
'/*头部右侧选中背景色 headerRightBgThis */\n' +
'.layui-layout-admin .layui-header .layuimini-header-content > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover {\n' +
' background-color: ' + bgcolorData.headerRightBgThis + ' !important;\n' +
'}\n' +
'\n' +
'/*头部右侧字体颜色 headerRightColor */\n' +
'.layui-layout-admin .layui-header .layui-nav .layui-nav-item a {\n' +
' color: ' + bgcolorData.headerRightColor + ';\n' +
'}\n' +
'/**头部右侧下拉字体颜色 headerRightChildColor */\n' +
'.layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child a {\n' +
' color: ' + bgcolorData.headerRightChildColor + '!important;\n' +
'}\n'+
'\n' +
'/*头部右侧鼠标选中 headerRightColorThis */\n' +
'.layui-header .layuimini-menu-header-pc.layui-nav .layui-nav-item a:hover, .layui-header .layuimini-header-menu.layuimini-pc-show.layui-nav .layui-this a {\n' +
' color: ' + bgcolorData.headerRightColorThis + ' !important;\n' +
'}\n' +
'\n' +
'/*头部右侧更多下拉颜色 headerRightNavMore */\n' +
'.layui-header .layui-nav .layui-nav-more {\n' +
' border-top-color: ' + bgcolorData.headerRightNavMore + ' !important;\n' +
'}\n' +
'\n' +
'/*头部右侧更多下拉颜色 headerRightNavMore */\n' +
'.layui-header .layui-nav .layui-nav-mored, .layui-header .layui-nav-itemed > a .layui-nav-more {\n' +
' border-color: transparent transparent ' + bgcolorData.headerRightNavMore + ' !important;\n' +
'}\n' +
'\n' +
'/**头部右侧更多下拉配置色 headerRightNavMoreBg headerRightNavMoreColor */\n' +
'.layui-header .layui-nav .layui-nav-child dd.layui-this a, .layui-header .layui-nav-child dd.layui-this, .layui-layout-admin .layui-header .layui-nav .layui-nav-item .layui-nav-child .layui-this a {\n' +
' background-color: ' + bgcolorData.headerRightNavMoreBg + ' !important;\n' +
' color:' + bgcolorData.headerRightNavMoreColor + ' !important;\n' +
'}\n' +
'\n' +
'/*头部缩放按钮样式 headerRightToolColor */\n' +
'.layui-layout-admin .layui-header .layuimini-tool i {\n' +
' color: ' + bgcolorData.headerRightToolColor + ';\n' +
'}\n' +
'\n' +
'/*logo背景颜色 headerLogoBg */\n' +
'.layui-layout-admin .layuimini-logo {\n' +
' background-color: ' + bgcolorData.headerLogoBg + ' !important;\n' +
'}\n' +
'\n' +
'/*logo字体颜色 headerLogoColor */\n' +
'.layui-layout-admin .layuimini-logo h1 {\n' +
' color: ' + bgcolorData.headerLogoColor + ';\n' +
'}\n' +
'\n' +
'/*左侧菜单更多下拉样式 leftMenuNavMore */\n' +
'.layuimini-menu-left .layui-nav .layui-nav-more,.layuimini-menu-left-zoom.layui-nav .layui-nav-more {\n' +
' border-top-color: ' + bgcolorData.leftMenuNavMore + ';\n' +
'}\n' +
'\n' +
'/*左侧菜单更多下拉样式 leftMenuNavMore */\n' +
'.layuimini-menu-left .layui-nav .layui-nav-mored, .layuimini-menu-left .layui-nav-itemed > a .layui-nav-more, .layuimini-menu-left-zoom.layui-nav .layui-nav-mored, .layuimini-menu-left-zoom.layui-nav-itemed > a .layui-nav-more {\n' +
' border-color: transparent transparent ' + bgcolorData.leftMenuNavMore + ' !important;\n' +
'}\n' +
'\n' +
'/*左侧菜单背景 leftMenuBg */\n' +
'.layui-side.layui-bg-black, .layui-side.layui-bg-black > .layuimini-menu-left > ul, .layuimini-menu-left-zoom > ul {\n' +
' background-color: ' + bgcolorData.leftMenuBg + ' !important;\n' +
'}\n' +
'\n' +
'/*左侧菜单选中背景 leftMenuBgThis */\n' +
'.layuimini-menu-left .layui-nav-tree .layui-this, .layuimini-menu-left .layui-nav-tree .layui-this > a, .layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this, .layuimini-menu-left .layui-nav-tree .layui-nav-child dd.layui-this a, .layuimini-menu-left-zoom.layui-nav-tree .layui-this, .layuimini-menu-left-zoom.layui-nav-tree .layui-this > a, .layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this, .layuimini-menu-left-zoom.layui-nav-tree .layui-nav-child dd.layui-this a {\n' +
' background-color: ' + bgcolorData.leftMenuBgThis + ' !important\n' +
'}\n' +
'\n' +
'/*左侧菜单子菜单背景 leftMenuChildBg */\n' +
'.layuimini-menu-left .layui-nav-itemed > .layui-nav-child{\n' +
' background-color: ' + bgcolorData.leftMenuChildBg + ' !important;\n' +
'}\n' +
'\n' +
'/*左侧菜单字体颜色 leftMenuColor */\n' +
'.layuimini-menu-left .layui-nav .layui-nav-item a, .layuimini-menu-left-zoom.layui-nav .layui-nav-item a {\n' +
' color: ' + bgcolorData.leftMenuColor + ' !important;\n' +
'}\n' +
'\n' +
'/*左侧菜单选中字体颜色 leftMenuColorThis */\n' +
'.layuimini-menu-left .layui-nav .layui-nav-item a:hover, .layuimini-menu-left .layui-nav .layui-this a, .layuimini-menu-left-zoom.layui-nav .layui-nav-item a:hover, .layuimini-menu-left-zoom.layui-nav .layui-this a {\n' +
' color:' + bgcolorData.leftMenuColorThis + ' !important;\n' +
'}\n' +
'\n' +
'/**tab选项卡选中颜色 tabActiveColor */\n' +
'.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active {\n' +
' background-color: ' + bgcolorData.tabActiveColor + ';\n' +
'}\n';
$('#layuimini-bg-color').html(styleHtml);
},
/**
* 构建主题选择html
* @param options
* @returns {string}
*/
buildBgColorHtml: function (options) {
options.bgColorDefault = options.bgColorDefault || 0;
var bgcolorId = parseInt(sessionStorage.getItem('layuiminiBgcolorId'));
if (isNaN(bgcolorId)) bgcolorId = options.bgColorDefault;
var bgColorConfig = miniTheme.config();
var html = '';
$.each(bgColorConfig, function (key, val) {
if (key === bgcolorId) {
html += '<li class="layui-this" data-select-bgcolor="' + key + '">\n';
} else {
html += '<li data-select-bgcolor="' + key + '">\n';
}
html += '<a href="javascript:;" data-skin="skin-blue" style="" class="clearfix full-opacity-hover">\n' +
'<div><span style="display:block; width: 20%; float: left; height: 12px; background: ' + val.headerLogoBg + ';"></span><span style="display:block; width: 80%; float: left; height: 12px; background: ' + val.headerRightBg + ';"></span></div>\n' +
'<div><span style="display:block; width: 20%; float: left; height: 40px; background: ' + val.leftMenuBg + ';"></span><span style="display:block; width: 80%; float: left; height: 40px; background: #ffffff;"></span></div>\n' +
'</a>\n' +
'</li>';
});
return html;
},
/**
* 监听
* @param options
*/
listen: function (options) {
$('body').on('click', '[data-bgcolor]', function () {
var loading = layer.load(0, {shade: false, time: 2 * 1000});
var clientHeight = (document.documentElement.clientHeight) - 60;
var bgColorHtml = miniTheme.buildBgColorHtml(options);
var html = '<div class="layuimini-color">\n' +
'<div class="color-title">\n' +
'<span>配色方案</span>\n' +
'</div>\n' +
'<div class="color-content">\n' +
'<ul>\n' + bgColorHtml + '</ul>\n' +
'</div>\n' +
'</div>';
layer.open({
type: 1,
title: false,
closeBtn: 0,
shade: 0.2,
anim: 2,
shadeClose: true,
id: 'layuiminiBgColor',
area: ['340px', clientHeight + 'px'],
offset: 'rb',
content: html,
success: function (index, layero) {
},
end: function () {
$('.layuimini-select-bgcolor').removeClass('layui-this');
}
});
layer.close(loading);
});
$('body').on('click', '[data-select-bgcolor]', function () {
var bgcolorId = $(this).attr('data-select-bgcolor');
$('.layuimini-color .color-content ul .layui-this').attr('class', '');
$(this).attr('class', 'layui-this');
sessionStorage.setItem('layuiminiBgcolorId', bgcolorId);
miniTheme.render({
bgColorDefault: bgcolorId,
listen: false,
});
});
}
};
exports("miniTheme", miniTheme);
})
;
+248
View File
@@ -0,0 +1,248 @@
/**
* date:2020/02/27
* author:Mr.Chung
* version:2.0
* description:layuimini 主体框架扩展
*/
layui.define(["jquery","element", "miniTab"], function (exports) {
var $ = layui.$,
layer = layui.layer,
dropdown = layui.dropdown,
element = layui.element ,
miniTab = layui.miniTab;
if (!/http(s*):\/\//.test(location.href)) {
var tips = "请先将项目部署至web容器(Apache/Tomcat/Nginx/IIS/等),否则部分数据将无法显示";
return layer.alert(tips);
}
var xphp = {
/**
* 后台框架初始化
* @param options.iniUrl 后台初始化接口地址
* @param options.urlHashLocation URL地址hash定位
* @param options.bgColorDefault 默认皮肤
* @param options.multiModule 是否开启多模块
* @param options.menuChildOpen 是否展开子菜单
* @param options.loadingTime 初始化加载时间
* @param options.pageAnim iframe窗口动画
* @param options.maxTabNum 最大的tab打开数量
*/
render: function (options) {
options.iniUrl = options.iniUrl || null;
options.urlHashLocation = options.urlHashLocation || false;
options.bgColorDefault = options.bgColorDefault || 0;
options.multiModule = options.multiModule || false;
options.menuChildOpen = options.menuChildOpen || false;
options.loadingTime = options.loadingTime || 0;
options.pageAnim = options.pageAnim || false;
options.maxTabNum = options.maxTabNum || 200;
options.isHideOpenMenu = !options.isHideOpenMenu ? options.isHideOpenMenu : true;
$.getJSON(options.iniUrl, function (data) {
if (data == null) {
xphp.error('暂无菜单信息')
} else {
xphp.renderHome(data.homeInfo);
xphp.renderAnim(options.pageAnim);
xphp.listen();
dropdown.render({
elem: '.menuitemon',
data:data.menuInfo,
customName: {
id: 'id',
title: 'title',
children: 'children'
},
trigger: 'hover',
click: function(obj){
miniTab.openNewTab({...obj,href:obj.dizhi});
}
});
//tab页
miniTab.render({
filter: 'layuiminiTab',
urlHashLocation: options.urlHashLocation,
multiModule: options.multiModule,
menuChildOpen: options.menuChildOpen,
maxTabNum: options.maxTabNum,
menuList: data.menuInfo,
homeInfo: data.homeInfo,
switchtoindex:options.switchtoindex||false,
listenSwichCallback: function () {
xphp.renderDevice();
}
});
xphp.deleteLoader(options.loadingTime);
xphp.isHideOpenMenu(options.isHideOpenMenu);
}
}).fail(function () {
xphp.error('菜单接口有误');
});
},
/**
* 点击左侧下拉菜单,关闭其他下拉菜单
* @param data
*/
isHideOpenMenu: function (data) {
$(".layui-side").on("click", ".layui-nav-item", function () {
if (data) {
$(this).siblings('li').attr('class', 'layui-nav-item');
}
});
},
/**
* 初始化首页
* @param data
*/
renderHome: function (data) {
sessionStorage.setItem('layuiminiHomeHref', data.href);
$('#layuiminiHomeTabId').html('<span class="layuimini-tab-active"></span><span class="disable-close">' + data.title + '</span><i class="layui-icon layui-unselect layui-tab-close">ဆ</i>');
$('#layuiminiHomeTabId').attr('lay-id', data.id);
$('#layuiminiHomeTabIframe').html('<iframe width="100%" height="100%" frameborder="no" border="0" marginwidth="0" marginheight="0" src="' + data.href + '"></iframe>');
},
/**
* 初始化iframe窗口动画
* @param anim
*/
renderAnim: function (anim) {
if (anim) {
$('#layuimini-bg-color').after('<style id="layuimini-page-anim">' +
'.layui-tab-item.layui-show {animation:moveTop 1s;-webkit-animation:moveTop 1s;animation-fill-mode:both;-webkit-animation-fill-mode:both;position:relative;height:100%;-webkit-overflow-scrolling:touch;}\n' +
'@keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}\n' +
'@-o-keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}\n' +
'@-moz-keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}\n' +
'@-webkit-keyframes moveTop {0% {opacity:0;-webkit-transform:translateY(30px);-ms-transform:translateY(30px);transform:translateY(30px);}\n' +
' 100% {opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);}\n' +
'}' +
'</style>');
}
},
/**
* 初始化设备端
*/
renderDevice: function () {
if (xphp.checkMobile()) {
$('.layuimini-tool i').attr('data-side-fold', 1);
$('.layuimini-tool i').attr('class', 'layui-icon layui-icon-list');
$('.layui-layout-body').removeClass('layuimini-mini');
$('.layui-layout-body').addClass('layuimini-all');
}
},
/**
* 初始化加载时间
* @param loadingTime
*/
deleteLoader: function (loadingTime) {
if (loadingTime) {
setTimeout(function () {
$('.layuimini-loader').fadeOut();
}, loadingTime * 1000)
} else {
$('.layuimini-loader').fadeOut();
}
},
/**
* 成功
* @param title
* @returns {*}
*/
success: function (title) {
return layer.msg(title, {icon: 1, shade: this.shade, scrollbar: false, time: 2000, shadeClose: true});
},
/**
* 失败
* @param title
* @returns {*}
*/
error: function (title) {
return layer.msg(title, {icon: 2, shade: this.shade, scrollbar: false, time: 3000, shadeClose: true});
},
/**
* 判断是否为手机
* @returns {boolean}
*/
checkMobile: function () {
var ua = navigator.userAgent.toLocaleLowerCase();
var pf = navigator.platform.toLocaleLowerCase();
var isAndroid = (/android/i).test(ua) || ((/iPhone|iPod|iPad/i).test(ua) && (/linux/i).test(pf))
|| (/ucweb.*linux/i.test(ua));
var isIOS = (/iPhone|iPod|iPad/i).test(ua) && !isAndroid;
var isWinPhone = (/Windows Phone|ZuneWP7/i).test(ua);
var clientWidth = document.documentElement.clientWidth;
if (!isAndroid && !isIOS && !isWinPhone && clientWidth > 1024) {
return false;
} else {
return true;
}
},
/**
* 监听
*/
listen: function () {
/**
* 监听提示信息
*/
$("body").on("mouseenter", ".layui-nav-tree .menu-li", function () {
if (xphp.checkMobile()) {
return false;
}
var classInfo = $(this).attr('class'),
tips = $(this).prop("innerHTML"),
isShow = $('.layuimini-tool i').attr('data-side-fold');
if (isShow == 0 && tips) {
tips = "<ul class='layuimini-menu-left-zoom layui-nav layui-nav-tree layui-this'><li class='layui-nav-item layui-nav-itemed'>"+tips+"</li></ul>" ;
window.openTips = layer.tips(tips, $(this), {
tips: [2, '#2f4056'],
time: 300000,
skin:"popup-tips",
success:function (el) {
var left = $(el).position().left - 10 ;
$(el).css({ left:left });
element.render();
}
});
}
});
$("body").on("mouseleave", ".popup-tips", function () {
if (xphp.checkMobile()) {
return false;
}
var isShow = $('.layuimini-tool i').attr('data-side-fold');
if (isShow == 0) {
try {
layer.close(window.openTips);
} catch (e) {
console.log(e.message);
}
}
});
/**
* 点击遮罩层
*/
$('body').on('click', '.layuimini-make', function () {
xphp.renderDevice();
});
}
};
exports("xphp", xphp);
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+101
View File
@@ -0,0 +1,101 @@
.ew-map-select-tool {
padding: 5px 15px;
box-shadow: 0 1px 0 0 rgba(0, 0, 0, .05);
}
.inline-block {
display: inline-block;
}
.layui-btn.icon-btn {
padding: 0 10px;
}
.pull-right {
float: right;
}
.map-select:after, .map-select:before {
content: '';
display: block;
clear: both;
}
.ew-map-select-poi {
height: 505px;
width: 250px;
overflow-x: hidden;
overflow-y: auto;
float: left;
position: relative;
display: block;
box-sizing: border-box;
}
.ew-map-select-search-list-item {
padding: 10px 30px 10px 15px;
border-bottom: 1px solid #e8e8e8;
cursor: pointer;
position: relative;
}
.ew-map-select-search-list-item .ew-map-select-search-list-item-title {
font-size: 14px;
color: #262626;
}
.ew-map-select-search-list-item .ew-map-select-search-list-item-address {
font-size: 12px;
color: #595959;
padding-top: 5px;
}
.ew-map-select-search-list-item-icon-ok {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
}
#ew-map-select-tips {
position: absolute;
z-index: 999;
background: #fff;
max-height: 430px;
overflow: auto;
top: 48px;
left: 56px;
width: 280px;
box-shadow: 0 2px 4px rgba(0,0,0,.12);
border: 1px solid #d2d2d2;
}
#ew-map-select-tips .ew-map-select-search-list-item {
padding: 10px 15px 10px 35px;
}
.ew-map-select-search-list-item-icon-search {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.ew-map-select-search-list-item .ew-map-select-search-list-item-title {
font-size: 14px;
color: #262626;
}
.ew-map-select-search-list-item .ew-map-select-search-list-item-address {
font-size: 12px;
color: #595959;
padding-top: 5px;
}
.cur-load0 {
display: none;
background: url('./img/location.cur');
}
.cur-load1 {
display: none;
background: url('./img/location_blue.cur');
}
+759
View File
@@ -0,0 +1,759 @@
layui.define(['layer', 'locationX'], function (exports) {
var $ = layui.jquery,
layer = layui.layer,
MOD_NAME = "location",
GPS = layui.locationX;
var tpl0 = '<div class="cur-load0"></div>\n' +
'<div class="cur-load1"></div>\n' +
'<div class="ew-map-select-tool" style="position: relative;">\n' +
' 经度:<input id="lng" class="layui-input inline-block" style="width: 190px;" autocomplete="off"/>\n' +
' &nbsp;&nbsp;&nbsp;纬度:<input id="lat" class="layui-input inline-block" style="width: 190px;" autocomplete="off"/>\n' +
' <button id="ew-map-select-btn-ok" class="layui-btn icon-btn pull-right" type="button"><i\n' +
' class="layui-icon">&#xe605;</i>确定\n' +
' </button>\n' +
'</div>\n' +
'<div id="map" style="width: 100%;height: calc(100% - 48px);"></div>';
var tpl1 ='<div class="cur-load0"></div>\n' +
'<div class="cur-load1"></div>\n' +
'<div class="ew-map-select-tool" style="position: relative;">\n' +
' 搜索:<input id="ew-map-select-input-search" class="layui-input icon-search inline-block" style="width: 190px;" placeholder="输入关键字搜索" autocomplete="off" />\n' +
' <div id="ew-map-select-tips" class="ew-map-select-search-list layui-hide" style="left: 0px;width: 248px;"></div>\n' +
' &nbsp;&nbsp;经度:<input id="lng" class="layui-input inline-block" style="width: 190px;" autocomplete="off" />\n' +
' &nbsp;&nbsp;&nbsp;纬度:<input id="lat" class="layui-input inline-block" style="width: 190px;" autocomplete="off" />\n' +
' <button id="ew-map-select-btn-ok" class="layui-btn icon-btn pull-right" type="button"><i class="layui-icon">&#xe605;</i>确定</button>\n' +
'</div>\n' +
'<div class="map-select">\n' +
'\n' +
' <div id="map" style="width: 600px;height: 505px;float: right;"></div>\n' +
' <div id="ew-map-select-poi" class="layui-col-sm5 ew-map-select-search-list ew-map-select-poi">\n' +
' </div>\n' +
'\n' +
'</div>';
var obj = function (config) {
this.config = {
// 默认中心点位置是北京天安门,所有坐标系都用此坐标,偏的不大
type: 0, // 0 : 仅定位 1: 带有搜索的定位
longitude: 116.404,
latitude: 39.915,
title: '定位',
zoom: 18,
apiType: "baiduMap",
coordinate: "baiduMap",
mapType: 0,
searchKey: '村',
init: function () {
return {longitude: 116.404, latitude: 39.915};
},
success: function () {
},
onClickTip: function (data) {
console.log(data);
}
}
this.config = $.extend(this.config, config);
// 初始化经纬度信息
var initData = this.config.init();
this.config.longitude = initData.longitude;
this.config.latitude = initData.latitude;
this.lng = this.config.longitude;
this.lat = this.config.latitude;
// 转换初始坐标
this.initCoordinate = function (lng, lat) {
var o = this;
if (o.config.apiType == o.config.coordinate) {
return {lng: lng, lat: lat};
} else if (o.config.apiType == 'baiduMap' && o.config.coordinate == 'tiandiMap') {
var res = GPS.WGS84_bd(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'tiandiMap' && o.config.coordinate == 'baiduMap') {
var res = GPS.bd_WGS84(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'gaodeMap' && o.config.coordinate == 'baiduMap') {
var res = GPS.bd_decrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'baiduMap' && o.config.coordinate == 'gaodeMap') {
var res = GPS.bd_encrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'gaodeMap' && o.config.coordinate == 'tiandiMap') {
var res = GPS.gcj_encrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'tiandiMap' && o.config.coordinate == 'gaodeMap') {
var res = GPS.gcj_decrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
}
}
if (this.config.longitude && this.config.latitude && this.config.mapType != this.config.coordinate) {
var tbd = this.initCoordinate(this.config.longitude, this.config.latitude);
this.config.longitude = tbd.lng;
this.config.latitude = tbd.lat;
}
this.transformCoordinate = function (lng, lat) {
var o = this;
if (o.config.apiType == o.config.coordinate) {
return {lng: lng, lat: lat};
} else if (o.config.apiType == 'baiduMap' && o.config.coordinate == 'tiandiMap') {
var res = GPS.bd_WGS84(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'tiandiMap' && o.config.coordinate == 'baiduMap') {
var res = GPS.WGS84_bd(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'gaodeMap' && o.config.coordinate == 'baiduMap') {
var res = GPS.bd_encrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'baiduMap' && o.config.coordinate == 'gaodeMap') {
var res = GPS.bd_decrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'gaodeMap' && o.config.coordinate == 'tiandiMap') {
var res = GPS.gcj_decrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
} else if (o.config.apiType == 'tiandiMap' && o.config.coordinate == 'gaodeMap') {
var res = GPS.gcj_encrypt(lat, lng);
return {lng: res.lon.toFixed(5), lat: res.lat.toFixed(5)};
}
}
this.openBaiduMap = function () {
var o = this;
var map; // 创建地图实例
if (o.config.mapType == 1) {
map = new BMap.Map("map", {enableMapClick: false, mapType: BMAP_SATELLITE_MAP});
} else if (o.config.mapType == 2) {
map = new BMap.Map("map", {enableMapClick: false, mapType: BMAP_HYBRID_MAP});
} else {
map = new BMap.Map("map", {enableMapClick: false, mapType: BMAP_NORMAL_MAP});
}
map.enableScrollWheelZoom(); //启用滚轮放大缩小,默认禁用
var point = new BMap.Point(o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915); // 创建点坐标
map.centerAndZoom(point, o.config.zoom);
map.setDefaultCursor("url('" + layui.cache.base + "location/img/location.cur') 17 35,auto"); //设置地图默认的鼠标指针样式
var marker = new BMap.Marker(map.getCenter()); // 创建标注
map.addOverlay(marker); // 将标注添加到地图中
map.addEventListener("click", function (e) {
var tbd = o.transformCoordinate(e.point.lng, e.point.lat);
//显示经纬度
$("#lng").val(tbd.lng);
$("#lat").val(tbd.lat);
o.lng = tbd.lng;
o.lat = tbd.lat;
var point = new BMap.Point(e.point.lng, e.point.lat);
map.removeOverlay(marker);
marker = new BMap.Marker(point);
map.addOverlay(marker);
if (o.config.type==1){
searchNearBy(e.point.lng, e.point.lat);
}
});
// 标记中心点
var markCenter = function (lng, lat){
var tbd = o.transformCoordinate(lng, lat);
//显示经纬度
$("#lng").val(tbd.lng);
$("#lat").val(tbd.lat);
o.lng = tbd.lng;
o.lat = tbd.lat;
var point = new BMap.Point(lng, lat);
map.removeOverlay(marker);
marker = new BMap.Marker(point);
map.addOverlay(marker);
if (o.config.type==1){
searchNearBy(lng, lat);
}
}
// 搜索附近方法
var searchNearBy = function (lng, lat){
var point = new BMap.Point(lng, lat);
var localSearch = new BMap.LocalSearch(point, {
pageCapacity: 10,
onSearchComplete: function (result){
var htmlList = '';
$.each(result,function (i,val){
$.each(val.Hr,function (i,ad){
htmlList += '<div data-lng="' + ad.point.lng + '" data-lat="' + ad.point.lat + '" data-title="'+ ad.title +'" data-address="'+ ad.address +'" class="ew-map-select-search-list-item">';
htmlList += ' <div class="ew-map-select-search-list-item-title">' + ad.title + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-address">' + ad.address + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-icon-ok layui-hide"><i class="layui-icon layui-icon-ok-circle"></i></div>';
htmlList += '</div>';
});
});
$('#ew-map-select-poi').html(htmlList);
}
});
localSearch.searchNearby([o.config.searchKey,'镇','街道','店'],point,1000);
}
// 初始化搜索
if (o.config.type==1){
o.initBaiduSearch(map,searchNearBy,markCenter);
}
}
this.initBaiduSearch = function (map,searchNearBy,markCenter){
var o = this;
searchNearBy(o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915);
// poi列表点击事件
$('#ew-map-select-poi').off('click').on('click', '.ew-map-select-search-list-item', function () {
$('#ew-map-select-tips').addClass('layui-hide');
$('#ew-map-select-poi .ew-map-select-search-list-item-icon-ok').addClass('layui-hide');
$(this).find('.ew-map-select-search-list-item-icon-ok').removeClass('layui-hide');
$('#ew-map-select-center-img').removeClass('bounceInDown');
setTimeout(function () {
$('#ew-map-select-center-img').addClass('bounceInDown');
});
var lng = $(this).data('lng');
var lat = $(this).data('lat');
//
var point = new BMap.Point(lng, lat);
map.centerAndZoom(point, map.getZoom());
markCenter(lng, lat);
var title = $(this).data('title');
var address = $(this).data('address');
o.config.onClickTip({title:title,address:address,lng:lng,lat:lat});
});
// 搜索提示
var $inputSearch = $('#ew-map-select-input-search');
$inputSearch.off('input').on('input', function () {
var keywords = $(this).val();
var $selectTips = $('#ew-map-select-tips');
if (!keywords) {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
var autoComplete = new BMap.LocalSearch('全国', {
pageCapacity: 10,
onSearchComplete: function (result){
if (undefined == result){
return ;
}
var htmlList = '';
$.each(result.Hr,function (i,ad){
htmlList += '<div data-lng="' + ad.point.lng + '" data-lat="' + ad.point.lat + '" data-title="'+ ad.title +'" data-address="'+ ad.address +'" class="ew-map-select-search-list-item">';
htmlList += ' <div class="ew-map-select-search-list-item-icon-search"><i class="layui-icon layui-icon-search"></i></div>';
htmlList += ' <div class="ew-map-select-search-list-item-title">' + ad.title + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-address">' + ad.address + '</div>';
htmlList += '</div>';
});
$selectTips.html(htmlList);
if (result.Hr.length === 0) $('#ew-map-select-tips').addClass('layui-hide');
else $('#ew-map-select-tips').removeClass('layui-hide');
}
});
autoComplete.search(keywords);
});
$inputSearch.off('blur').on('blur', function () {
var keywords = $(this).val();
var $selectTips = $('#ew-map-select-tips');
if (!keywords) {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
});
$inputSearch.off('focus').on('focus', function () {
var keywords = $(this).val();
if (keywords) $('#ew-map-select-tips').removeClass('layui-hide');
});
// tips列表点击事件
$('#ew-map-select-tips').off('click').on('click', '.ew-map-select-search-list-item', function () {
$('#ew-map-select-tips').addClass('layui-hide');
var lng = $(this).data('lng');
var lat = $(this).data('lat');
var point = new BMap.Point(lng, lat);
map.centerAndZoom(point, map.getZoom());
markCenter(lng, lat);
var title = $(this).data('title');
var address = $(this).data('address');
o.config.onClickTip({title:title,address:address,lng:lng,lat:lat});
});
}
this.openTiandiMap = function () {
var o = this;
var map = new T.Map("map"); // 创建地图实例
if (o.config.mapType == 1) {
map.setMapType(TMAP_SATELLITE_MAP);
} else if (o.config.mapType == 2) {
map.setMapType(TMAP_HYBRID_MAP);
} else {
map.setMapType(TMAP_NORMAL_MAP);
}
map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
var latLng = new T.LngLat(o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915);
map.centerAndZoom(latLng, o.config.zoom);
var marker = new T.Marker(latLng); // 创建标注
map.addOverLay(marker);// 将标注添加到地图中
if (undefined === window.T.MarkTool) {
setTimeout(function () {
initMarkerTool();
}, 200);
} else {
initMarkerTool();
}
function initMarkerTool() {
var markerTool = new T.MarkTool(map, {follow: true});
markerTool.open();
/*标注事件*/
var mark = function (e) {
$.each(map.getOverlays(), function (i, marker) {
if (marker != e.currentMarker) {
map.removeOverLay(marker);
}
})
//显示经纬度
var tbd = o.transformCoordinate(e.currentLnglat.getLng(), e.currentLnglat.getLat());
$("#lng").val(tbd.lng);
$("#lat").val(tbd.lat);
o.lng = tbd.lng;
o.lat = tbd.lat;
markerTool = new T.MarkTool(map, {follow: true});
markerTool.open();
markerTool.addEventListener("mouseup", mark);
if (o.config.type==1){
searchNearBy(e.currentLnglat.getLng(), e.currentLnglat.getLat());
}
}
//绑定mouseup事件 在用户每完成一次标注时触发事件。
markerTool.addEventListener("mouseup", mark);
}
// 标记中心点
var markCenter = function (lng, lat) {
$.each(map.getOverlays(), function (i, marker) {
map.removeOverLay(marker);
})
//显示经纬度
var tbd = o.transformCoordinate(lng, lat);
$("#lng").val(tbd.lng);
$("#lat").val(tbd.lat);
o.lng = tbd.lng;
o.lat = tbd.lat;
var latLng = new T.LngLat(lng, lat);
var marker = new T.Marker(latLng); // 创建标注
map.addOverLay(marker);// 将标注添加到地图中
if (o.config.type==1){
searchNearBy(lng, lat);
}
}
// 搜索附近方法
var searchNearBy = function (lng, lat){
var point = new T.LngLat(lng,lat);
var localSearch = new T.LocalSearch(map, {
pageCapacity: 10,
onSearchComplete: function (result){
var htmlList = '';
$.each(result.getPois(),function (i,ad){
var lnglat = ad.lonlat.split(" ");
htmlList += '<div data-lng="' + lnglat[0] + '" data-lat="' + lnglat[1] + '" data-title="'+ ad.name +'" data-address="'+ ad.address +'" class="ew-map-select-search-list-item">';
htmlList += ' <div class="ew-map-select-search-list-item-title">' + ad.name + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-address">' + ad.address + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-icon-ok layui-hide"><i class="layui-icon layui-icon-ok-circle"></i></div>';
htmlList += '</div>';
});
$('#ew-map-select-poi').html(htmlList);
}
});
localSearch.setQueryType(1);
localSearch.searchNearby(o.config.searchKey,point,1000);
}
if (o.config.type==1){
o.initTiandiSearch(map,searchNearBy,markCenter);
}
}
this.initTiandiSearch = function (map,searchNearBy,markCenter){
var o = this;
searchNearBy(o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915);
// poi列表点击事件
$('#ew-map-select-poi').off('click').on('click', '.ew-map-select-search-list-item', function () {
$('#ew-map-select-tips').addClass('layui-hide');
$('#ew-map-select-poi .ew-map-select-search-list-item-icon-ok').addClass('layui-hide');
$(this).find('.ew-map-select-search-list-item-icon-ok').removeClass('layui-hide');
$('#ew-map-select-center-img').removeClass('bounceInDown');
setTimeout(function () {
$('#ew-map-select-center-img').addClass('bounceInDown');
});
var lng = $(this).data('lng');
var lat = $(this).data('lat');
//
var point = new T.LngLat(lng, lat);
map.centerAndZoom(point, map.getZoom());
markCenter(lng, lat);
var title = $(this).data('title');
var address = $(this).data('address');
o.config.onClickTip({title:title,address:address,lng:lng,lat:lat});
});
// 搜索提示
var $inputSearch = $('#ew-map-select-input-search');
$inputSearch.off('input').on('input', function () {
var keywords = $(this).val();
var $selectTips = $('#ew-map-select-tips');
if (!keywords) {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
var autoComplete = new T.LocalSearch(map, {
pageCapacity: 10,
onSearchComplete: function (result){
if (undefined == result){
return ;
}
var htmlList = '';
$.each(result.getPois(),function (i,ad){
var lnglat = ad.lonlat.split(" ");
htmlList += '<div data-lng="' + lnglat[0] + '" data-lat="' + lnglat[1] + '" data-title="'+ ad.name +'" data-address="'+ ad.address +'" class="ew-map-select-search-list-item">';
htmlList += ' <div class="ew-map-select-search-list-item-title">' + ad.name + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-address">' + ad.address + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-icon-ok layui-hide"><i class="layui-icon layui-icon-ok-circle"></i></div>';
htmlList += '</div>';
});
$selectTips.html(htmlList);
if (result.getPois().length === 0) $('#ew-map-select-tips').addClass('layui-hide');
else $('#ew-map-select-tips').removeClass('layui-hide');
}
});
autoComplete.setQueryType(1);
autoComplete.search(keywords);
});
$inputSearch.off('blur').on('blur', function () {
var keywords = $(this).val();
var $selectTips = $('#ew-map-select-tips');
if (!keywords) {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
});
$inputSearch.off('focus').on('focus', function () {
var keywords = $(this).val();
if (keywords) $('#ew-map-select-tips').removeClass('layui-hide');
});
// tips列表点击事件
$('#ew-map-select-tips').off('click').on('click', '.ew-map-select-search-list-item', function () {
$('#ew-map-select-tips').addClass('layui-hide');
var lng = $(this).data('lng');
var lat = $(this).data('lat');
var point = new T.LngLat(lng, lat);
map.centerAndZoom(point, map.getZoom());
markCenter(lng, lat);
var title = $(this).data('title');
var address = $(this).data('address');
o.config.onClickTip({title:title,address:address,lng:lng,lat:lat});
});
}
this.openGaodeMap = function () {
var o = this;
// 创建地图实例
var layers = [];
if (o.config.mapType == '1') {
var satellite = new AMap.TileLayer.Satellite();
layers.push(satellite);
} else if (o.config.mapType == '2') {
var satellite = new AMap.TileLayer.Satellite();
var roadNet = new AMap.TileLayer.RoadNet();
layers.push(satellite);
layers.push(roadNet);
} else {
var layer = new AMap.TileLayer();
layers.push(layer);
}
var map = new AMap.Map("map",
{
resizeEnable: true,
zoom: o.config.zoom,
center: [o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915],
layers: layers
});
map.setDefaultCursor("url('" + layui.cache.base + "location/img/location_blue.cur') 17 35,auto");
// 初始化中间点标记
var marker = new AMap.Marker({
icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png",
position: [o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915]
});
map.add(marker);
var markCenter = function (e) {
// 标记中心点
map.clearMap();
// alert('您在[ '+e.lnglat.getLng()+','+e.lnglat.getLat()+' ]的位置点击了地图!');
//显示经纬度
var tbd = o.transformCoordinate(e.lng, e.lat);
$("#lng").val(tbd.lng);
$("#lat").val(tbd.lat);
o.lng = tbd.lng;
o.lat = tbd.lat;
var marker = new AMap.Marker({
icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png",
position: [e.lng, e.lat]
});
map.add(marker);
if (o.config.type == 1) {
searchNearBy(e.lng, e.lat);
}
}
var clickHandler = function (e) {
markCenter({lng: e.lnglat.getLng(), lat: e.lnglat.getLat()});
};
// 绑定事件
map.on('click', clickHandler);
// 附近搜索方法
var searchNearBy = function (lng, lat) {
AMap.service(['AMap.PlaceSearch'], function () {
var placeSearch = new AMap.PlaceSearch({
type: '', pageSize: 10, pageIndex: 1
});
var cpoint = [lng, lat];
placeSearch.searchNearBy('', cpoint, 1000, function (status, result) {
if (status === 'complete') {
var pois = result.poiList.pois;
var htmlList = '';
for (var i = 0; i < pois.length; i++) {
var poiItem = pois[i];
if (poiItem.location !== undefined) {
htmlList += '<div data-lng="' + poiItem.location.lng + '" data-lat="' + poiItem.location.lat + '" data-title="'+ poiItem.name +'" data-address="'+ poiItem.address +'" class="ew-map-select-search-list-item">';
htmlList += ' <div class="ew-map-select-search-list-item-title">' + poiItem.name + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-address">' + poiItem.address + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-icon-ok layui-hide"><i class="layui-icon layui-icon-ok-circle"></i></div>';
htmlList += '</div>';
}
}
$('#ew-map-select-poi').html(htmlList);
}
});
});
};
// 初始化search
if (o.config.type == 1) {
o.initGaodeSearch(map, markCenter, searchNearBy);
}
}
this.initGaodeSearch = function (map, markCenter, searchNearBy) {
var o = this;
// poi列表点击事件
$('#ew-map-select-poi').off('click').on('click', '.ew-map-select-search-list-item', function () {
$('#ew-map-select-tips').addClass('layui-hide');
$('#ew-map-select-poi .ew-map-select-search-list-item-icon-ok').addClass('layui-hide');
$(this).find('.ew-map-select-search-list-item-icon-ok').removeClass('layui-hide');
$('#ew-map-select-center-img').removeClass('bounceInDown');
setTimeout(function () {
$('#ew-map-select-center-img').addClass('bounceInDown');
});
var lng = $(this).data('lng');
var lat = $(this).data('lat');
var name = $(this).find('.ew-map-select-search-list-item-title').text();
var address = $(this).find('.ew-map-select-search-list-item-address').text();
//
map.setZoomAndCenter(map.getZoom(), [lng, lat]);
markCenter({lng: lng, lat: lat});
var title = $(this).data('title');
var address = $(this).data('address');
o.config.onClickTip({title:title,address:address,lng:lng,lat:lat});
});
searchNearBy(o.config.longitude ? o.config.longitude : 116.404, o.config.latitude ? o.config.latitude : 39.915);
// 搜索提示
var $inputSearch = $('#ew-map-select-input-search');
$inputSearch.off('input').on('input', function () {
var keywords = $(this).val();
var $selectTips = $('#ew-map-select-tips');
if (!keywords) {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
AMap.plugin('AMap.Autocomplete', function () {
var autoComplete = new AMap.Autocomplete({city: '全国'});
autoComplete.search(keywords, function (status, result) {
if (result.tips) {
var tips = result.tips;
var htmlList = '';
for (var i = 0; i < tips.length; i++) {
var tipItem = tips[i];
if (tipItem.location !== undefined) {
htmlList += '<div data-lng="' + tipItem.location.lng + '" data-lat="' + tipItem.location.lat + '" data-title="'+ tipItem.name +'" data-address="'+ tipItem.address +'" class="ew-map-select-search-list-item">';
htmlList += ' <div class="ew-map-select-search-list-item-icon-search"><i class="layui-icon layui-icon-search"></i></div>';
htmlList += ' <div class="ew-map-select-search-list-item-title">' + tipItem.name + '</div>';
htmlList += ' <div class="ew-map-select-search-list-item-address">' + tipItem.address + '</div>';
htmlList += '</div>';
}
}
$selectTips.html(htmlList);
if (tips.length === 0) $('#ew-map-select-tips').addClass('layui-hide');
else $('#ew-map-select-tips').removeClass('layui-hide');
} else {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
});
});
});
$inputSearch.off('blur').on('blur', function () {
var keywords = $(this).val();
var $selectTips = $('#ew-map-select-tips');
if (!keywords) {
$selectTips.html('');
$selectTips.addClass('layui-hide');
}
});
$inputSearch.off('focus').on('focus', function () {
var keywords = $(this).val();
if (keywords) $('#ew-map-select-tips').removeClass('layui-hide');
});
// tips列表点击事件
$('#ew-map-select-tips').off('click').on('click', '.ew-map-select-search-list-item', function () {
$('#ew-map-select-tips').addClass('layui-hide');
var lng = $(this).data('lng');
var lat = $(this).data('lat');
map.setZoomAndCenter(map.getZoom(), [lng, lat]);
markCenter({lng: lng, lat: lat});
var title = $(this).data('title');
var address = $(this).data('address');
o.config.onClickTip({title:title,address:address,lng:lng,lat:lat});
});
}
this.openMap = function () {
var o = this;
if (o.config.apiType == "baiduMap") {
var index = layer.open({
type: 1,
area: ["850px", "600px"],
title: o.config.title,
content: o.config.type == 0 ? tpl0:tpl1,
success: function () {
// 回显数据 中心标记经纬度
$("#lng").val(o.lng);
$("#lat").val(o.lat);
// 渲染地图
if (undefined === window.BMap) {
$.getScript("http://api.map.baidu.com/getscript?v=2.0&ak=tCNPmUfNmy4nTR3VYW71a6IgyWMaOSUb&services=&t=20200824135534", function () {
o.openBaiduMap();
});
} else {
o.openBaiduMap();
}
// 绑定事件
$("#ew-map-select-btn-ok").on("click", function () {
o.config.success({lng: o.lng ? o.lng : 116.404, lat: o.lat ? o.lat : 39.915});
layer.close(index);
})
}
});
} else if (o.config.apiType == "tiandiMap") {
var index = layer.open({
type: 1,
area: ["850px", "600px"],
title: o.config.title,
content: o.config.type == 0 ? tpl0:tpl1,
success: function () {
// 回显数据 中心标记经纬度
$("#lng").val(o.lng);
$("#lat").val(o.lat);
// 渲染地图
if (undefined === window.T) {
$.getScript("http://api.tianditu.gov.cn/api?v=4.0&tk=a8718394c98e9ae85b0d7af352653ce2&callback=init", function () {
o.openTiandiMap();
})
} else {
o.openTiandiMap();
}
// 绑定事件
$("#ew-map-select-btn-ok").on("click", function () {
o.config.success({lng: o.lng ? o.lng : 116.404, lat: o.lat ? o.lat : 39.915});
layer.close(index);
})
}
});
} else if (o.config.apiType == "gaodeMap") {
var index = layer.open({
type: 1,
area: ["850px", "600px"],
title: o.config.title,
content: o.config.type == 0 ? tpl0:tpl1,
success: function () {
// 回显数据 中心标记经纬度
$("#lng").val(o.lng);
$("#lat").val(o.lat);
// 渲染地图
if (undefined === window.AMap) {
$.getScript("https://webapi.amap.com/maps?v=1.4.14&key=006d995d433058322319fa797f2876f5", function () {
o.openGaodeMap();
});
} else {
o.openGaodeMap();
}
// 绑定事件
$("#ew-map-select-btn-ok").on("click", function () {
o.config.success({lng: o.lng ? o.lng : 116.404, lat: o.lat ? o.lat : 39.915});
layer.close(index);
})
}
});
}
}
};
layui.link(layui.cache.base + "location/location.css?v="+(new Date).getTime()); // 加载css
/*导出模块,用一个location对象来管理obj,不需要外部new obj*/
var location = function () {
}
location.prototype.render = function (elem, config) {
$(elem).on("click", function () {
var _this = new obj(config);
_this.openMap();
})
}
var locationObj = new location();
exports(MOD_NAME, locationObj);
})
+168
View File
@@ -0,0 +1,168 @@
layui.define(['layer'],function (exports) {
var $ = layui.jquery,
layer=layui.layer,
MOD_NAME = "locationX";
var GPS = {
PI : 3.14159265358979324,
x_pi : 3.14159265358979324 * 3000.0 / 180.0,
delta : function (lat, lon) {
// Krasovsky 1940
//
// a = 6378245.0, 1/f = 298.3
// b = a * (1 - f)
// ee = (a^2 - b^2) / a^2;
var a = 6378245.0; // a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
var ee = 0.00669342162296594323; // ee: 椭球的偏心率。
var dLat = this.transformLat(lon - 105.0, lat - 35.0);
var dLon = this.transformLon(lon - 105.0, lat - 35.0);
var radLat = lat / 180.0 * this.PI;
var magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
var sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * this.PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * this.PI);
return {'lat': dLat, 'lon': dLon};
},
//WGS-84 to GCJ-02
gcj_encrypt : function (wgsLat, wgsLon) {
if (this.outOfChina(wgsLat, wgsLon))
return {'lat': wgsLat, 'lon': wgsLon};
var d = this.delta(wgsLat, wgsLon);
return {'lat' : wgsLat + d.lat,'lon' : wgsLon + d.lon};
},
//GCJ-02 to WGS-84
gcj_decrypt : function (gcjLat, gcjLon) {
if (this.outOfChina(gcjLat, gcjLon))
return {'lat': gcjLat, 'lon': gcjLon};
var d = this.delta(gcjLat, gcjLon);
return {'lat': gcjLat - d.lat, 'lon': gcjLon - d.lon};
},
//GCJ-02 to WGS-84 exactly
gcj_decrypt_exact : function (gcjLat, gcjLon) {
var initDelta = 0.01;
var threshold = 0.000000001;
var dLat = initDelta, dLon = initDelta;
var mLat = gcjLat - dLat, mLon = gcjLon - dLon;
var pLat = gcjLat + dLat, pLon = gcjLon + dLon;
var wgsLat, wgsLon, i = 0;
while (1) {
wgsLat = (mLat + pLat) / 2;
wgsLon = (mLon + pLon) / 2;
var tmp = this.gcj_encrypt(wgsLat, wgsLon)
dLat = tmp.lat - gcjLat;
dLon = tmp.lon - gcjLon;
if ((Math.abs(dLat) < threshold) && (Math.abs(dLon) < threshold))
break;
if (dLat > 0) pLat = wgsLat; else mLat = wgsLat;
if (dLon > 0) pLon = wgsLon; else mLon = wgsLon;
if (++i > 10000) break;
}
//console.log(i);
return {'lat': wgsLat, 'lon': wgsLon};
},
//GCJ-02 to BD-09
bd_encrypt : function (gcjLat, gcjLon) {
var x = gcjLon, y = gcjLat;
var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * this.x_pi);
var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * this.x_pi);
bdLon = z * Math.cos(theta) + 0.0065;
bdLat = z * Math.sin(theta) + 0.006;
return {'lat' : bdLat,'lon' : bdLon};
},
//BD-09 to GCJ-02
bd_decrypt : function (bdLat, bdLon) {
var x = bdLon - 0.0065, y = bdLat - 0.006;
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.x_pi);
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.x_pi);
var gcjLon = z * Math.cos(theta);
var gcjLat = z * Math.sin(theta);
return {'lat' : gcjLat, 'lon' : gcjLon};
},
//
bd_WGS84:function(bdLat, bdLon){
var gcj=GPS.bd_decrypt(bdLat, bdLon);
return GPS.gcj_decrypt(gcj.lat,gcj.lon);
},
// 天地图坐标->百度坐标
WGS84_bd:function(bdLat, bdLon){
var gcj=GPS.gcj_encrypt(bdLat, bdLon);
return GPS.bd_encrypt(gcj.lat,gcj.lon);
},
//WGS-84 to Web mercator
//mercatorLat -> y mercatorLon -> x
mercator_encrypt : function(wgsLat, wgsLon) {
var x = wgsLon * 20037508.34 / 180.;
var y = Math.log(Math.tan((90. + wgsLat) * this.PI / 360.)) / (this.PI / 180.);
y = y * 20037508.34 / 180.;
return {'lat' : y, 'lon' : x};
/*
if ((Math.abs(wgsLon) > 180 || Math.abs(wgsLat) > 90))
return null;
var x = 6378137.0 * wgsLon * 0.017453292519943295;
var a = wgsLat * 0.017453292519943295;
var y = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
return {'lat' : y, 'lon' : x};
//*/
},
// Web mercator to WGS-84
// mercatorLat -> y mercatorLon -> x
mercator_decrypt : function(mercatorLat, mercatorLon) {
var x = mercatorLon / 20037508.34 * 180.;
var y = mercatorLat / 20037508.34 * 180.;
y = 180 / this.PI * (2 * Math.atan(Math.exp(y * this.PI / 180.)) - this.PI / 2);
return {'lat' : y, 'lon' : x};
/*
if (Math.abs(mercatorLon) < 180 && Math.abs(mercatorLat) < 90)
return null;
if ((Math.abs(mercatorLon) > 20037508.3427892) || (Math.abs(mercatorLat) > 20037508.3427892))
return null;
var a = mercatorLon / 6378137.0 * 57.295779513082323;
var x = a - (Math.floor(((a + 180.0) / 360.0)) * 360.0);
var y = (1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * mercatorLat) / 6378137.0)))) * 57.295779513082323;
return {'lat' : y, 'lon' : x};
//*/
},
// two point's distance
distance : function (latA, lonA, latB, lonB) {
var earthR = 6371000.;
var x = Math.cos(latA * this.PI / 180.) * Math.cos(latB * this.PI / 180.) * Math.cos((lonA - lonB) * this.PI / 180);
var y = Math.sin(latA * this.PI / 180.) * Math.sin(latB * this.PI / 180.);
var s = x + y;
if (s > 1) s = 1;
if (s < -1) s = -1;
var alpha = Math.acos(s);
var distance = alpha * earthR;
return distance;
},
outOfChina : function (lat, lon) {
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
},
transformLat : function (x, y) {
var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * this.PI) + 40.0 * Math.sin(y / 3.0 * this.PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * this.PI) + 320 * Math.sin(y * this.PI / 30.0)) * 2.0 / 3.0;
return ret;
},
transformLon : function (x, y) {
var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * this.PI) + 20.0 * Math.sin(2.0 * x * this.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * this.PI) + 40.0 * Math.sin(x / 3.0 * this.PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * this.PI) + 300.0 * Math.sin(x / 30.0 * this.PI)) * 2.0 / 3.0;
return ret;
}
};
exports(MOD_NAME,GPS);
})
@@ -0,0 +1,96 @@
/**
消息盒子容器
*/
.lay-jsan-notice-marker {
position: absolute;
}
/**
消息盒子基础样式
*/
.lay-jsan-notice-marker-box {
/*position: absolute;*/
width: 35px;
height: 35px;
border: 1px solid #e2e2e2;
text-align: center;
line-height: 35px;
color: #e2e2e2;
float: left;
background-color: #ffffff;
}
/**
消息盒子鼠标悬停样式
*/
.lay-jsan-notice-marker-box:hover {
background-color: #f2f2f2;
color: #1E9FFF;
}
/**
消息盒子中图标样式
*/
.lay-jsan-notice-marker-icon {
font-size: 26px!important;
}
/**
最新消息,消息盒子样式
*/
.lay-jsan-notice-marker-news {
color: #FF5722!important;
}
/**
消息盒子操作按钮
*/
.lay-jsan-notice-marker-btn {
/*position: absolute;*/
width: 15px;
height: 35px;
border: 1px solid #e2e2e2;
text-align: center;
line-height: 35px;
color: #e2e2e2;
float: left;
background-color: #ffffff;
font-size: 16px;
}
.lay-jsan-notice-marker-btn:hover {
background-color: #f2f2f2;
color: #1E9FFF;
}
.lay-jsan-notice-marker-item {
padding: 5px 0 5px 10px;
background-color: #f2f2f2;
border-radius: 5px;
margin-bottom: 12px;
}
.lay-jsan-notice-marker-item:hover {
background-color: #dddddd;
cursor: pointer;
}
.lay-jsan-notice-marker-item-title-new {
color: #FF5722;
}
.lay-jsan-notice-marker-item-title {
font-size: 14px;
font-weight: bold;
}
.lay-jsan-notice-marker-item-date {
font-size: 10px;
color: #d2d2d2;
padding: 2px 0 2px 0;
}
.lay-jsan-notice-marker-item-content {
font-size: 12px;
color: #d2d2d2;
}
@@ -0,0 +1,243 @@
// noinspection ThisExpressionReferencesGlobalObjectJS
/**
* 基于layui v-2.5.4 版本,封装的消息组件
* 作者:jsan
* 日期:2019-07-28
*/
(function (root, factroy) {
typeof root.layui === "object" && layui.define ? layui.define(["layer"], function(mods){mods("jsanNotice", factroy(layui.layer))}) : factroy(root.layer);
}(this, function (layer) {
// //引入css
layui.link(layui.cache.base+"mods/extend/jsan-notice.css?v="+(new Date).getTime());
/**
* 消息盒子方法
* @param option 参数对象:
* elem 元素选择器,如:#test
* positionX 盒子左右定位位置[right,left],默认right
* positionY 盒子相对位置,可以选择不同的单位长度,如:100px
* lowKey true隐藏,false显示
* noticeWindow 详细消息窗口属性
*/
layer.noticeMarker = function (option) {
const $ = layui.$,
that = {},
POSITION_X_STYLE = typeof option["positionX"] === "undefined" || option["positionX"] === "right" ? "right: 1px;" : option["positionX"]+" 1px;",
POSITION_Y_STYPE = typeof option["positionY"] === "undefined" ? "top: 0;" : "top: "+option["positionY"]+";",
MARKER = "lay-jsan-notice-marker",
MARKER_BOX = "lay-jsan-notice-marker-box",
MARKER_BOX_NEWS = "lay-jsan-notice-marker-news",
MARKER_BOX_ICON = "layui-icon layui-icon-speaker lay-jsan-notice-marker-icon",
MARKER_BOX_BTN = "lay-jsan-notice-marker-btn",
MARKER_BOX_HIDE_BTN_ICON = "layui-icon layui-icon-"+(typeof option["positionX"] === "undefined" || option["positionX"] === "right" ? "right" : "left"),
MARKER_BOX_SHOW_BTN_ICON = "layui-icon layui-icon-"+(typeof option["positionX"] === "undefined" || option["positionX"] === "right" ? "left" : "right");
that.properties = {}; //初始化属性
$(option.elem).hide(); //隐藏初始化元素
that.properties.index = NOTICE_MARKER_INDEX++; //消息框唯一标识
that.properties.isOpen = option["lowKey"]; //初始化是否显示
that.properties.option = option; //录入初始化配置
that.properties.option.positionX = typeof option["positionX"] === "undefined" ? "right" : option["positionX"]; //初始化定位
that.properties.option.positionY = typeof option["positionY"] === "undefined" ? "right" : option["positionY"]; //初始化定位
that.properties.marker = $("<div id='notice-marker-"+that.properties.index+"' class='"+MARKER+"' style='"+POSITION_X_STYLE+POSITION_Y_STYPE+"'></div>"); //容器
that.properties.markerBoxBtn = $("<div class='"+MARKER_BOX_BTN+"'></div>"); //提示显示角标
that.properties.markerBoxBtnIcon = $("<i class='"+MARKER_BOX_HIDE_BTN_ICON+"'></i>"); //提示显示角标
that.properties.markerBox = $("<div class='"+MARKER_BOX+"'></div>"); //消息盒子
that.properties.markerBoxIcon = $("<i class='"+MARKER_BOX_ICON+"'></i>"); //消息盒子图标
//初始化默认方法
/**
* 消息提醒方法
* @param option 参数对象
* lowKey true隐藏,false显示
*/
that.remind = function(option) {
if(option["lowKey"] && that.properties.isOpen) {
//提醒时不弹出
this.hideBox();
}else if(!option["lowKey"] && !that.properties.isOpen) {
this.showBox();
}
this.properties.markerBox.addClass(MARKER_BOX_NEWS);
this.properties.markerBoxBtn.addClass(MARKER_BOX_NEWS);
};
/**
* 隐藏消息盒子方法
*/
that.hideBox = function() {
if(this.properties.isOpen) {
this.properties.markerBox.hide();
this.properties.markerBoxBtnIcon.removeClass(MARKER_BOX_HIDE_BTN_ICON);
this.properties.markerBoxBtnIcon.addClass(MARKER_BOX_SHOW_BTN_ICON);
this.properties.isOpen = false;
}
};
/**
* 显示消息盒子方法
*/
that.showBox = function() {
if(!this.properties.isOpen) {
this.properties.markerBox.show();
this.properties.markerBoxBtnIcon.removeClass(MARKER_BOX_SHOW_BTN_ICON);
this.properties.markerBoxBtnIcon.addClass(MARKER_BOX_HIDE_BTN_ICON);
this.properties.isOpen = true;
}
};
//封装渲染
that.properties.markerBoxBtn.html(that.properties.markerBoxBtnIcon);
that.properties.markerBox.html(that.properties.markerBoxIcon);
that.properties.marker.html(that.properties.option["positionX"] === "left" ? that.properties.markerBox : that.properties.markerBoxBtn);
that.properties.marker.append(that.properties.option["positionX"] === "left" ? that.properties.markerBoxBtn : that.properties.markerBox);
$("body").append(that.properties.marker);
//隐藏/显示事件
that.properties.markerBoxBtn.unbind().on("click", that, function (event) {
event.data.properties.isOpen ? event.data.hideBox() : event.data.showBox();
});
//初始化详细消息窗口
/**
* type 1:组件自带消息窗口,2:打开用户自定义窗口,默认是1
* title 消息窗口标题
* classType 消息类型(type=1时生效) 属于Object类型 {"id": "name"} 如:{"notice": "通知", "alerted": "预警", "other": "其他"}
* url 自定义消息窗口时打开的链接
* width 消息窗口宽度 可以选择不同的单位长度,如:100px
* height 消息窗口高度 可以选择不同的单位长度,如:100px
* contentWidth 消息内容窗口宽度
* contentHeight 消息内容窗口高度
*/
if(typeof that.properties.option.noticeWindow === "object" && that.properties.option.noticeWindow["type"] !== 2) {
that.noticeWindow = {};
that.noticeWindow.index = that.properties.index;
that.noticeWindow.width = typeof that.properties.option.noticeWindow["width"] === "string" ? that.properties.option.noticeWindow["width"] : "150px";
that.noticeWindow.height = typeof that.properties.option.noticeWindow["height"] === "string" ? that.properties.option.noticeWindow["height"] : "560px";
that.noticeWindow.contentWidth = typeof that.properties.option.noticeWindow["contentWidth"] === "string" ? that.properties.option.noticeWindow["contentWidth"] : "650px";
that.noticeWindow.contentHeight = typeof that.properties.option.noticeWindow["contentHeight"] === "string" ? that.properties.option.noticeWindow["contentHeight"] : "560px";
that.noticeWindow.window = $("<div id='notice-marker-window-"+that.noticeWindow.index+"' class='layui-tab' lay-filter='notice-marker-window-"+that.noticeWindow.index+"'></div>");
that.noticeWindow.tabTitle = $("<ul id='notice-marker-window-title-"+that.noticeWindow.index+"' class='layui-tab-title'></ul>");
that.noticeWindow.tabContent = $("<div id='notice-marker-window-content-"+that.noticeWindow.index+"' class='layui-tab-content'></div>");
const classType = {};
if(typeof that.properties.option.noticeWindow["classType"] === "object") {
for(let tab in that.properties.option.noticeWindow["classType"]) {
classType[tab] = ["<li id='notice-marker-window-title-"+tab+"'>"+that.properties.option.noticeWindow["classType"][tab]+"<span class='layui-badge-dot layui-hide'></span></li>", "<div id='notice-marker-window-content-"+tab+"' lay-id='notice-marker-window-content-"+tab+"' class='layui-tab-item'></div>"];
}
}else {
classType['notice'] = ["<li id='notice-marker-window-title-notice'>消息</li>", "<div id='notice-marker-window-content-notice' lay-id='notice-marker-window-content-\"+tab+\"' class='layui-tab-item'></div>"];
}
that.noticeWindow.classType = classType;
//详细消息窗口渲染
that.noticeWindow.window.html(that.noticeWindow.tabTitle);
that.noticeWindow.window.append(that.noticeWindow.tabContent);
for(let tab in that.noticeWindow.classType) {
that.noticeWindow.tabTitle.append(that.noticeWindow.classType[tab][0]);
that.noticeWindow.tabContent.append(that.noticeWindow.classType[tab][1]);
}
that.noticeWindow.window.hide();
that.noticeWindow.tabTitle.find("li").eq(0).addClass("layui-this");
that.noticeWindow.tabContent.find(".layui-tab-item").eq(0).addClass("layui-show");
$("body").append(that.noticeWindow.window);
layui.use('element', function(){});
that.properties.markerBox.unbind().on("click", that, function (event) {
event.data.hideBox();
layer.open({
type: 1,
id: "notice-marker-window-layer-"+that.noticeWindow.index,
title: typeof event.data.properties.option.noticeWindow["title"] === "string" ? event.data.properties.option.noticeWindow["title"] : "<i class='layui-icon layui-icon-friends'></i>",
area: [event.data.noticeWindow.width - 12, event.data.noticeWindow.height],
offset: [event.data.properties.option.positionY, (that.properties.option["positionX"] === "right" ? ($("body").width()-16-Number(that.noticeWindow.width.replace("px", "")))+"px" : "16px")],
shade: 0,
maxmin: true,
content: $("#"+event.data.noticeWindow.window.attr("id")),
cancel: function () {
that.noticeWindow.window.hide();
}
});
event.data.properties.markerBox.removeClass(MARKER_BOX_NEWS);
event.data.properties.markerBoxBtn.removeClass(MARKER_BOX_NEWS);
});
/**
* 向消息窗口推送消息
* @param option 参数对象
* lowKey 是否使用盒子提醒 true不提醒,false提醒
* classTypeId 消息所属消息类型的id
* content 需要推送的类型集合 Array,每组数据包括:
* title 消息标题。最大27位长度,大于27会自动省略
* content 消息内容。最大44位长度,大于44位自动省略
* date 消息发布时间 yyyy-MM-dd HH:mm:ss
* url 点击消息后跳转位置
*/
that.addNews = function (option) {
for(let i in option.content) {
const item = $("<div class='lay-jsan-notice-marker-item' notice-url = '" + option.content[i]["url"] + "'></div>");
item.append("<div class='lay-jsan-notice-marker-item-title lay-jsan-notice-marker-item-title-new'>"+(option.content[i]["title"].length > 28 ? option.content[i]["title"].substring(0, 25)+"..." : option.content[i]["title"] )+"</div>");
item.append("<div class='lay-jsan-notice-marker-item-date'>"+option.content[i]["date"]+"</div>");
item.append("<div class='lay-jsan-notice-marker-item-content'>"+(option.content[i]["content"].length > 45 ? option.content[i]["content"].substring(0, 43)+"..." : option.content[i]["content"])+"</div>");
$("#notice-marker-window-content-"+option["classTypeId"]).prepend(item);
}
$("#notice-marker-window-title-"+option["classTypeId"]).find(".layui-badge-dot").removeClass("layui-hide");
noticeMarkerItemEvent(option, this);
const lowKey = typeof option["lowKey"] === "undefined" ? false : option["lowKey"];
this.remind({"lowKey": lowKey});
};
var noticeMarkerItemEvent = function (option, that) {
$("#notice-marker-window-content-"+option["classTypeId"]+" .lay-jsan-notice-marker-item").unbind().on("click", function (event) {
$(this).find(".lay-jsan-notice-marker-item-title").eq(0).removeClass("lay-jsan-notice-marker-item-title-new");
if($("#notice-marker-window-content-"+option["classTypeId"]).find(".lay-jsan-notice-marker-item-title-new").length === 0) {
$("#notice-marker-window-title-"+option["classTypeId"]).find(".layui-badge-dot").addClass("layui-hide");
}
$(this).attr("notice-url");
layer.open({
type: 2,
title: that.properties.option.noticeWindow["title"],
area: [that.noticeWindow.contentWidth, that.noticeWindow.contentHeight],
shade: 0,
maxmin: true,
content: $(this).attr("notice-url")
});
});
}
}else if(typeof that.properties.option.noticeWindow === "object" && that.properties.option.noticeWindow["type"] === 2) {
that.noticeWindow = {};
that.noticeWindow.index = that.properties.index;
that.noticeWindow.url = that.properties.option.noticeWindow["url"];
that.noticeWindow.width = typeof that.properties.option.noticeWindow["width"] === "string" ? that.properties.option.noticeWindow["width"] : "150px";
that.noticeWindow.height = typeof that.properties.option.noticeWindow["height"] === "string" ? that.properties.option.noticeWindow["height"] : "560px";
that.properties.markerBox.unbind().on("click", that, function (event) {
event.data.hideBox();
layer.open({
type: 2,
id: "notice-marker-window-layer-"+that.noticeWindow.index,
title: typeof event.data.properties.option.noticeWindow["title"] === "string" ? event.data.properties.option.noticeWindow["title"] : "<i class='layui-icon layui-icon-friends'></i>",
area: [event.data.noticeWindow.width, event.data.noticeWindow.height],
offset: [event.data.properties.option.positionY, (that.properties.option["positionX"] === "right" ? ($("body").width()-16-Number(that.noticeWindow.width.replace("px", "")))+"px" : "16px")],
shade: 0,
maxmin: true,
content: event.data.noticeWindow.url
});
});
}
//初始显示设置
that.properties.isOpen ? that.hideBox() : that.showBox();
return that;
};
return {mod: "jsanNotice", v: "1.0.11"};
}));
NOTICE_MARKER_INDEX = 1;
+78
View File
@@ -0,0 +1,78 @@
(function(root,factroy){
typeof root.layui === 'object' && layui.define ? layui.define(function(mods){mods('mods',factroy(layui))}) : null;
}(this,function(layui){
'use strict';
// 预定义插件列表
var list = {
jsanNotice:'mods/extend/jsan-notice'
};
// 插件加载器
var mods = function(mod_name,callback){
var extend = {};
// 如果是官方模块
// 引入单个插件
if(typeof mod_name === 'string'){
if(!isLayui(mod_name)){
if(typeof list[mod_name] !== 'string') throw new Error('引入的插件'+mod_name+'不在预定义列表中');
extend[mod_name] = list[mod_name];
}
}
// 批量引入插件
else if(Array.isArray(mod_name)){
for(var i=0,item;item = mod_name[i++];){
if(!isLayui(item)){
if(typeof list[item] !== 'string') throw new Error('引入的插件'+item+'不在预定义列表中');
extend[item] = list[item];
}
}
}
else{
throw new Error('mods()中,传入了无效的参数');
}
if(typeof callback !== 'function') throw Error('第二个参数必须是函数');
layui.extend(extend).use(mod_name,function(){
var arg = [];
for(var i=0,item;item = arguments[i++];){
arg.push(item);
}
callback.apply(layui,arg);
});
}
var isLayui = function(mod){
return typeof layui_mods[mod] === 'string' ? true : false;
};
if(typeof Array.isArray !== 'function'){
Array.isArray = function(val){
return Object.prototype.toString.call(val) === '[object Array]' ? true : false;
}
}
var layui_mods = {
layer:'layer',
laydate:'laydate',
layedit:'layedit',
laypage:'laypage',
laytpl:'laytpl',
table:'table',
form:'form',
upload:'upload',
jquery:'jquery',
code:'code',
carousel:'carousel',
element:'element',
flow:'flow',
mobile:'mobile',
rate:'rate',
tree:'tree',
util:'util',
};
return mods;
}));
+101
View File
@@ -0,0 +1,101 @@
/**
* @Name: 基于layui
* @Author: 潘晨晨
* 最近修改时间: 2021/04/22
*/
layui.define(['jquery'],function(exports){
var $ = layui.jquery;
var obj ={
init:function(element){
//默认
element.data = element.data || [ {name:'暂无数据'}]
element.rows = element.rows || 1
element.moreUpText = element.moreUpText || '更多'
element.moreDownText = element.moreDownText || '收起'
element.href = element.href || false
element.herfBlank = element.herfBlank?'_blank':'_self'
element.themeColor = element.themeColor || 'green'
element.size = element.size ? 'layui-btn-'+element.size :'layui-btn'
var html;
var box = $(element.elemId);
var boxHeight ;
var itemHeight ;
var flag = true; // 如果外面包裹了pack的变false
var dyc = false;
box.addClass('box-item-pcc');
element.data.forEach(e=>{
boxHeight = box.height();
itemHeight = $('.item-pcc').outerHeight(true);
element.href ? html = '<a class="item-pcc layui-bg-'+element.themeColor+' '+element.size+'" href="'+element.href+'?id='+e.id+'" target="'+element.herfBlank+'">'+e.name+'</a>':html = '<span class="item-pcc layui-bg-'+element.themeColor+' '+element.size+'">'+e.name+'</span>'
if((boxHeight>itemHeight*element.rows) && flag){
morePosition();
flag =false;
}
box.append(html);
})
boxHeight = box.height();
itemHeight = $('.item-pcc').outerHeight(true);
if(boxHeight>itemHeight*element.rows){
more(); //第一次渲染页面
dyc =true
}
$(document).on('click','#more-pcc',function(){ //点击更多
more()
})
function morePosition(el){
if(flag){
if(el&&dyc){ //如果不是第一次渲染并且
box.find('#more-box-pcc').remove();
}
else{
$('.item-pcc').wrapAll("<span class='pack-pcc'></span>")
}
var list = $('.pack-pcc .item-pcc').eq(-3);
list.before('<span id="more-box-pcc" class="item-pcc more-pcc '+element.size+'"><a class="layui-font-'+element.themeColor+' " id="more-pcc">'+element.moreUpText+'</a></span>');
}
}
function more(){
if(box.height()>itemHeight*element.rows){
box.css('height',itemHeight*element.rows);
morePosition(true)
}else{
box.css('height','auto');
box.find('#more-box-pcc').remove();
box.append('<span id="more-box-pcc" class="item-pcc more-pcc '+element.size+'"><a class="layui-font-'+element.themeColor+'" id="more-pcc">'+element.moreDownText+'</a></span>');
flag = true;
}
}
}
}
var $style = $('<style type="text/css">\
.box-item-pcc { overflow: hidden; display: inline-block; width: 70%;} \
.box-item-pcc .item-pcc { margin:0 5px 5px 5px; box-sizing: border-box; display: inline-block; }\
.box-item-pcc .more-pcc { float: right; background: none; }\
.box-item-pcc a { cursor: pointer; }\
.layui-font-red{color:#FF5722!important}\
.layui-font-orange{color:#FFB800!important}\
.layui-font-green{color:#009688!important}\
.layui-font-cyan{color:#2F4056!important}\
.layui-font-blue{color:#01AAED!important}\
.layui-font-black{color:#000!important}\
.layui-font-gray{color:#c2c2c2!important}\
</style>');
$($('head')[0]).append($style);
exports('moreMenus',obj);
});
+228
View File
@@ -0,0 +1,228 @@
.toast-title {
font-weight: bold;
}
.toast-message {
-ms-word-wrap: break-word;
word-wrap: break-word;
}
.toast-message a,
.toast-message label {
color: #FFFFFF;
}
.toast-message a:hover {
color: #CCCCCC;
text-decoration: none;
}
.toast-close-button {
position: relative;
right: -0.3em;
top: -0.3em;
float: right;
font-size: 20px;
font-weight: bold;
color: #FFFFFF;
-webkit-text-shadow: 0 1px 0 #ffffff;
text-shadow: 0 1px 0 #ffffff;
opacity: 0.8;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
filter: alpha(opacity=80);
line-height: 1;
}
.toast-close-button:hover,
.toast-close-button:focus {
color: #000000;
text-decoration: none;
cursor: pointer;
opacity: 0.4;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
filter: alpha(opacity=40);
}
.rtl .toast-close-button {
left: -0.3em;
float: left;
right: 0.3em;
}
/*Additional properties for button version
iOS requires the button element instead of an anchor tag.
If you want the anchor version, it requires `href="#"`.*/
button.toast-close-button {
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
}
.toast-top-center {
top: 0;
right: 0;
width: 100%;
}
.toast-bottom-center {
bottom: 0;
right: 0;
width: 100%;
}
.toast-top-full-width {
top: 0;
right: 0;
width: 100%;
}
.toast-bottom-full-width {
bottom: 0;
right: 0;
width: 100%;
}
.toast-top-left {
top: 12px;
left: 12px;
}
.toast-top-right {
top: 12px;
right: 12px;
}
.toast-bottom-right {
right: 12px;
bottom: 12px;
}
.toast-bottom-left {
bottom: 12px;
left: 12px;
}
#toast-container {
position: fixed;
z-index: 999999;
pointer-events: none;
/*overrides*/
}
#toast-container * {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
#toast-container > div {
position: relative;
pointer-events: auto;
overflow: hidden;
margin: 0 0 6px;
padding: 15px 15px 15px 50px;
width: 300px;
-moz-border-radius: 3px 3px 3px 3px;
-webkit-border-radius: 3px 3px 3px 3px;
border-radius: 3px 3px 3px 3px;
background-position: 15px center;
background-repeat: no-repeat;
-moz-box-shadow: 0 0 12px #999999;
-webkit-box-shadow: 0 0 12px #999999;
box-shadow: 0 0 12px #999999;
color: #FFFFFF;
opacity: 0.8;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
filter: alpha(opacity=80);
}
#toast-container > div.rtl {
direction: rtl;
padding: 15px 50px 15px 15px;
background-position: right 15px center;
}
#toast-container > div:hover {
-moz-box-shadow: 0 0 12px #000000;
-webkit-box-shadow: 0 0 12px #000000;
box-shadow: 0 0 12px #000000;
opacity: 1;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
filter: alpha(opacity=100);
cursor: pointer;
}
#toast-container > .toast-info {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
}
#toast-container > .toast-error {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
}
#toast-container > .toast-success {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
}
#toast-container > .toast-warning {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
}
#toast-container.toast-top-center > div,
#toast-container.toast-bottom-center > div {
width: 300px;
margin-left: auto;
margin-right: auto;
}
#toast-container.toast-top-full-width > div,
#toast-container.toast-bottom-full-width > div {
width: 96%;
margin-left: auto;
margin-right: auto;
}
.toast {
background-color: #030303;
}
.toast-success {
background-color: #51A351;
}
.toast-error {
background-color: #BD362F;
}
.toast-info {
background-color: #2F96B4;
}
.toast-warning {
background-color: #F89406;
}
.toast-progress {
position: absolute;
left: 0;
bottom: 0;
height: 4px;
background-color: #000000;
opacity: 0.4;
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
filter: alpha(opacity=40);
}
/*Responsive Design*/
@media all and (max-width: 240px) {
#toast-container > div {
padding: 8px 8px 8px 50px;
width: 11em;
}
#toast-container > div.rtl {
padding: 8px 50px 8px 8px;
}
#toast-container .toast-close-button {
right: -0.2em;
top: -0.2em;
}
#toast-container .rtl .toast-close-button {
left: -0.2em;
right: 0.2em;
}
}
@media all and (min-width: 241px) and (max-width: 480px) {
#toast-container > div {
padding: 8px 8px 8px 50px;
width: 18em;
}
#toast-container > div.rtl {
padding: 8px 50px 8px 8px;
}
#toast-container .toast-close-button {
right: -0.2em;
top: -0.2em;
}
#toast-container .rtl .toast-close-button {
left: -0.2em;
right: 0.2em;
}
}
@media all and (min-width: 481px) and (max-width: 768px) {
#toast-container > div {
padding: 15px 15px 15px 50px;
width: 25em;
}
#toast-container > div.rtl {
padding: 15px 50px 15px 15px;
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,84 @@
/**
@ Name:表格可展开显示更多列
@ Authorhbm
@ LicenseMIT
@ giteehttps://gitee.com/hbm_461/layui_extend_openTable
*/
/* 样式加载完毕的标识 */
html #layuicss-regionSelect {
display: none;
position: absolute;
width: 1989px;
}
.layui-openTable {
}
/* 组件样式 */
.openTable-i-table-open {
display: block;
width: 10px;
height: 10px;
user-select: none;
background: url(./right.svg) 0 0 no-repeat;
background-size: 10px 10px;
}
/*表格展开三角动画*/
.openTable-open-dow {
transform: rotate(90deg)
}
.openTable-i-table-open {
position: relative;
display: inline-block;
transition: transform .2s ease-in-out;
}
.openTable-open-td {
padding-bottom: 20px !important;
background-color: #fdfdfd !important;
}
.openTable-open-td:hover {
background-color: white;
}
/*展开列 容器*/
.openTable-open-item-div {
display: inline-block;
margin-top: 20px;
margin-right: 20px;
font-size: 16px;
}
/*展开列 title*/
.openTable-item-title {
color: #99a9bf;
}
/*展开列 可修改 */
.openTable-exp-value-edit {
background-color: #F6F6F6;
}
/*展开列 仅展示 */
.openTable-exp-value {
padding: 0 20px 0 20px;
min-width: 80px;
display: inline-block;
border: none;
border-bottom: #dedede solid 1px;
padding-bottom: 2px;
padding-top: 4px !important
}
.openTable-open-item-div input {
height: 29px !important;
}
+258
View File
@@ -0,0 +1,258 @@
/**
@ Name:表格冗余列可展开显示
@ Authorhbm
@ LicenseMIT
*/
layui.define(['form', 'table'], function (exports) {
var $ = layui.$
, table = layui.table
, form = layui.form
, VERSION = 1.0, MOD_NAME = 'openTable', ELEM = '.layui-openTable', ON = 'on', OFF = 'off'
//外部接口
, openTable = {
index: layui.openTable ? (layui.openTable.index + 10000) : 0
//设置全局项
, set: function (options) {
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件监听
, on: function (events, callback) {
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//操作当前实例
, thisIns = function () {
var that = this
, options = that.config
, id = options.id || options.index;
return {
reload: function (options) {
that.reload.call(that, options);
}
, config: options
}
}
//构造器
, Class = function (options) {
var that = this;
that.index = ++openTable.index;
that.config = $.extend({}, that.config, openTable.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
openType: 0
};
//渲染视图
Class.prototype.render = function () {
var that = this
, options = that.config
, colArr = options.cols[0]
, openCols = options.openCols || []
, done = options.done;
delete options["done"];
// 1、在第一列 插入可展开操作
colArr.splice(0, 0, {
align: 'left',
width: 50,
templet: function (item) {
return "<i class='openTable-i-table-open ' status='off' data='"
// 把当前列的数据绑定到控件
+ (JSON.stringify(item))
+ "' title='展开'></i>";
}
});
// 2、表格Render
table.render(
$.extend({
done: function (res, curr, count) {
initExpandedListener();
if (done) {
done(res, curr, count)
}
}
}, options));
// 3、展开事件
function initExpandedListener() {
//扩大点击事件范围 为父级div
$(".openTable-i-table-open")
.parent()
.unbind()
.click(function () {
var that = $(this).children();
// 关闭类型
if (options.openType === 0) {
var sta = $(".openTable-open-dow").attr("status"),
isThis = (that.attr("data") === $(".openTable-open-dow").attr("data"));
//1、关闭展开的
$(".openTable-open-dow")
.addClass("openTable-open-up")
.removeClass("openTable-open-dow")
.attr("status", OFF);
//2、如果当前 = 展开 && 不等于当前的 关闭
if (sta === ON && isThis) {
$(".openTable-open-td").slideUp(100, function () {
$(".openTable-open-td").remove();
});
return;
} else {
that.attr("status", OFF)
$(".openTable-open-td").remove();
}
}
var _this = this
, item = JSON.parse(that.attr("data"))
, status = that.attr("status") === 'on';
// 1、如果当前为打开,再次点击则关闭
if (status) {
that.removeClass("openTable-open-dow");
that.attr("status", 'off');
this.addTR.find("div").slideUp(100, function () {
_this.addTR.remove();
});
return;
}
var html = ["<div style='margin-left: 50px;display: none'>"];
// 2、从左到右依次排列 Item
openCols.forEach(function (val, index) {
// 1、自定义模板
if (val.templet) {
html.push("<div class='openTable-open-item-div'>")
html.push(val.templet(item));
html.push("</div>")
// 2、可下拉选择类型
} else if (val.type && val.type === 'select') {
var child = ["<div id='" + val.field + "' class='openTable-open-item-div' >"];
child.push("<span style='color: #99a9bf'>" + val["title"] + "</span>");
child.push("<div class='layui-input-inline'><select lay-filter='" + val.field + "'>");
val.items.forEach(function (it) {
it = val.onDraw(it, item);
child.push("<option value='" + it.id + "' ");
child.push(it.isSelect ? " selected='selected' " : "");
child.push(" >" + it.value + "</option>");
});
child.push("</select></div>");
child.push("</div>");
html.push(child.join(""));
setTimeout(function () {
layui.form.render();
// 监听 select 修改
layui.form.on('select(' + val.field + ')', function (data) {
if (options.edit && val.onSelect(data, item)) {
var json = {};
json.value = data.value;
json.field = val.field;
item[val.field] = data.value;
json.data = JSON.parse(JSON.stringify(item));
options.edit(json);
}
});
}, 20);
} else {
// 3、默认类型
html.push("<div class='openTable-open-item-div'>");
html.push("<span class='openTable-item-title'>" + val["title"] + "</span>");
html.push((val.edit ?
("<input class='openTable-exp-value openTable-exp-value-edit' autocomplete='off' name='" + val["field"] + "' value='" + item[val["field"]] + "'/>")
: ("<span class='openTable-exp-value' >" + item[val["field"]] + "</span>")
));
html.push("</div>");
}
});
that.addClass("openTable-open-dow");
// 把添加的 tr 绑定到当前 移除时使用
this.addTR = $([
"<tr><td class='openTable-open-td' colspan='" + (colArr.length + 1) + "'>"
, html.join("") + "</div>"
, "</td></tr>"].join("")
);
that.parent().parent().parent().after(this.addTR);
this.addTR.find("div").slideDown(200);
that.attr("status", 'on');
$(".openTable-exp-value-edit")
.blur(function () {
var that = $(this), name = that.attr("name"), val = that.val();
// 设置了回调 &&发生了修改
if (options.edit && item[name] + "" !== val) {
var json = {};
json.value = that.val();
json.field = that.attr("name");
item[name] = val;
json.data = item;
options.edit(json);
}
}).keypress(function (even) {
even.which === 13 && $(this).blur()
})
});
}
// 4、监听排序事件
var elem = $(options.elem).attr("lay-filter");
// 5、监听表格排序
table.on('sort(' + elem + ')', function (obj) {
if (options.sort) {
options.sort(obj)
}
// 重新绑定事件
initExpandedListener();
});
// 6、单元格编辑
layui.table.on('edit(' + elem + ')', function (obj) {
if (options.edit) {
options.edit(obj)
}
});
};
//核心入口
openTable.render = function (options) {
var ins = new Class(options);
return thisIns.call(ins);
};
//加载组件所需样式
layui.link(layui.cache.base + "openTable/openTable.css?v="+(new Date).getTime(), function () {
//此处的“openTable”要对应 openTable.css 中的样式: html #layuicss-openTable{}
}, 'openTable');
exports('openTable', openTable);
});
+1
View File
@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1574129071108" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="722" xmlns:xlink="http://www.w3.org/1999/xlink" width="512" height="512"><defs><style type="text/css"></style></defs><path d="M804.288 520.288c1.119-14.86-3.681-30.045-15.009-41.627l-446.179-446.499c-21.028-20.961-55.078-20.961-76.291 0.033-21.065 20.999-20.921 55.265-0.11 76.258l411.912 411.875-411.946 411.731c-20.849 21.098-21.176 55.046-0.071 76.187 21.279 21.031 55.222 20.993 76.363-0.038l446.323-446.148c11.4-11.472 16.128-26.658 15.009-41.772v0 0 0zM804.288 520.288z" p-id="723"></path></svg>

After

Width:  |  Height:  |  Size: 751 B

@@ -0,0 +1,316 @@
/*!
* passwordIntensity v1.0
* author JerryZst
* qq 1309579432
* Date: 2021/01/20 0007
*/
layui.define(['jquery', 'element'], function (exports) {
var $ = layui.jquery;
var element = layui.element;
var _MOD = 'passwordIntensity';
var passwordIntensity = function (opt) {
this.version = 'passwordIntensity-1.0';
this.tmpId = new Date().getTime();
this.tmpId = opt.uniqueId ? opt.uniqueId : this.tmpId + Math.round(Math.random() * 1000 + 9999);
this.passwordLevel = [
'low',
'middle',
'midhigh',
'high',
]
this._level = null;
// 配置项
this.options = $.extend(true, {
data: opt.data || '',
chang: opt.chang || 8,
on: opt.on || null,
}, opt);
this.init(); // 初始化
this.bindEvents(); // 绑定事件
};
/** 获取各个组件 */
passwordIntensity.prototype.getComponents = function () {
var that = this;
var $elem = $(that.options.elem);
var filter = $elem.attr('lay-filter');
if (!filter) {
filter = that.options.elem.substring(1);
$elem.attr('lay-filter', filter);
}
return {
$elem: $elem, // 容器
filter: filter, // 容器的lay-filter
};
};
// 初始化
passwordIntensity.prototype.init = function () {
var components = this.getComponents();
var html = "";
for (var i = 0; i < this.passwordLevel.length; i++) {
var color = "";
var name = "";
var levelId = this.tmpId + this.passwordLevel[i];
if (this.passwordLevel[i] === 'low') {
name = "弱";
color = "layui-bg-red";
} else if (this.passwordLevel[i] === 'middle') {
name = "中";
color = "layui-bg-orange";
} else if (this.passwordLevel[i] === 'midhigh') {
name = "中上";
color = "layui-bg-orange";
} else {
name = "强";
color = "layui-bg-green";
}
html += '<div class="layui-col-md3 layui-col-sm3 layui-col-xs3" style="text-align: center">' +
'<div class="layui-progress layui-progress-big" lay-filter="' + levelId + '">' +
'<div id="' + levelId + '" class="layui-progress-bar ' + color + '" lay-percent="0%">' + '</div>' +
'</div>' + '<span style="background: white;font-size: 12px">' + name + '</span></div>';
}
html = '<div id="' + this.tmpId + '" class="layui-row layui-col-space2" style="margin-top: 5px">' + html + '</div>';
components.$elem.parent('div').append(html);
if (this.options.data) {
components.$elem.val(this.options.data);
var that = this;
var _level = checkStrong(this.options.data,this.options.chang);
switch (_level) {
case 0:
that.setLevel('low', '100%');
break;
case 1:
that.setLevel('low', '100%');
break;
case 2:
that.setLevel('middle', '100%');
break;
case 3:
that.setLevel('midhigh', '100%');
break;
default:
that.setLevel('high', '100%');
break;
}
}
return html;
}
/**
* 绑定事件
*/
passwordIntensity.prototype.bindEvents = function () {
var components = this.getComponents();
var that = this;
// 实时输入事件
components.$elem.off('input propertychange').on('input propertychange', function () {
var pwd = $(this).val();
if (pwd == "" || pwd == null) {
that.setLevel('');
that._level = null;
} else {
var _level = checkStrong(pwd,that.options.chang);
that._level = _level;
switch (_level) {
case 0:
that.setLevel('low', '100%');
break;
case 1:
that.setLevel('low', '100%');
break;
case 2:
that.setLevel('middle', '100%');
break;
case 3:
that.setLevel('midhigh', '100%');
break;
default:
that.setLevel('high', '100%');
break;
}
}
});
// 光标消失事件
components.$elem.off('blur').on('blur', function () {
var pwd = $(this).val();
if (pwd == "" || pwd == null) {
that.setLevel('');
that._level = null;
} else {
var _level = checkStrong(pwd,that.options.chang);
that._level = _level;
switch (_level) {
case 0:
that.setLevel('low', '100%');
break;
case 1:
that.setLevel('low', '100%');
break;
case 2:
that.setLevel('middle', '100%');
break;
case 3:
that.setLevel('midhigh', '100%');
break;
default:
that.setLevel('high', '100%');
break;
}
}
});
}
/**
* 设置级别
*/
passwordIntensity.prototype.setLevel = function (level, value) {
value = value || '100%';
for (var i = 0; i < this.passwordLevel.length; i++) {
if (level === '') {
element.progress(this.tmpId + this.passwordLevel[i], '0%');
} else {
if (level === this.passwordLevel[i]) {
element.progress(this.tmpId + level, value);
} else {
if (value === '100%') {
element.progress(this.tmpId + this.passwordLevel[i], '0%');
}
}
}
}
return true;
}
/**
* 返回当前的密码级别
* @returns {string}
*/
passwordIntensity.prototype.getLevel = function () {
return _levelByName(this._level);
}
/**
* 当前密码是否弱
* @returns {boolean}
*/
passwordIntensity.prototype.isLow = function () {
return _levelByName(this._level) === 'low' || this._level === null;
}
/**
* 当前密码是否中
* @returns {boolean}
*/
passwordIntensity.prototype.isMiddle = function () {
return _levelByName(this._level) === 'middle';
}
/**
* 当前密码是否强
* @returns {boolean}
*/
passwordIntensity.prototype.isHigh = function () {
return _levelByName(this._level) === 'high';
}
/**
* 当前密码是否强
* @returns {boolean}
*/
passwordIntensity.prototype.ismidHigh = function () {
return _levelByName(this._level) === 'midhigh';
}
/**
* 级别转换
* @param level
* @returns {string}
* @private
*/
function _levelByName(level) {
var name = 'low';
switch (level) {
case 0:
name = "low";
break;
case 1:
name = "low";
break;
case 2:
name = "middle";
//that.setLevel('middle', '100%');
break;
case 3:
name = "midhigh";
//that.setLevel('midhigh', '100%');
break;
default:
name = "high";
break;
}
return name;
}
/**
* 监听事件 // 预留
* @param events
* @param callback
* @returns {*}
*/
passwordIntensity.prototype.on = function (events, callback) {
return layui.onevent.call(this, _MOD, events, callback);
};
//判断输入密码的类型
function charMode(iN) {
if (iN >= 48 && iN <= 57) //数字
return 1;
if (iN >= 65 && iN <= 90) //大写
return 2;
if (iN >= 97 && iN <= 122) //小写
return 4;
else
return 8;
}
//计算密码模式
function bitTotal(num) {
modes = 0;
for (i = 0; i < 4; i++) {
if (num & 1) modes++;
num >>>= 1;
}
return modes;
}
//返回强度级别
function checkStrong(sPW,chang) {
if (sPW.length <= 6) {
return 0; //密码太短
}
if(sPW.length < chang){
return 0;
}
Modes = 0;
for (i = 0; i < sPW.length; i++) {
//密码模式
Modes |= charMode(sPW.charCodeAt(i));
}
return bitTotal(Modes);
}
/** 外部方法 */
var iS = {
/* 渲染 */
render: function (options) {
return new passwordIntensity(options);
},
/* 事件监听 */
on: function (events, callback) {
return layui.onevent.call(this, _MOD, events, callback);
}
};
exports(_MOD, iS);
});
@@ -0,0 +1,59 @@
/**
@ Namelayui.regionCheckBox 中国省市复选框
@ Authorwanmianji
*/
html #layuicss-regionCheckBox {
display: none;
position: absolute;
width: 1989px;
}
.layui-regionContent {
margin: 6px;
border: 1px solid #e6e6e6;
}
.layui-regionContent .all {
margin-left: 15px;
}
.layui-regionContent .area {
margin-bottom: 0;
}
.layui-regionContent .area label {
width: 45px;
}
.layui-regionContent .area .province {
margin-left: 75px;
}
.layui-regionContent .province ul li {
float: left;
position: relative;
border: 1px solid #fff;
padding: 9px 0 9px 15px;
}
.layui-regionContent .province ul li .layui-form-checkbox[lay-skin=primary] {
margin-top: 0;
}
.layui-regionContent .province ul li.parent:hover {
border: 1px solid #e4e4e4;
}
.layui-regionContent .province .city{
position: absolute;
background: #fff;
width: 330px;
left: -1px;
top: 100%;
z-index: 2;
line-height: 26px;
border: 1px solid #e4e4e4;
padding: 6px 0 6px 15px;
display: none;
}
@@ -0,0 +1,292 @@
/**
@ Namelayui.regionCheckBox 中国省市复选框
@ Authorwanmianji
*/
layui.define('form', function(exports){
'use strict';
var $ = layui.$
,form = layui.form
,MOD_NAME = 'regionCheckBox', ELEM_CLASS = 'layui-regionContent'
,regionCheckBox = {
index: layui.regionCheckBox ? (layui.regionCheckBox.index + 10000) : 0
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
,thisIns = function(){
var that = this
,options = that.config
,id = options.id || options.index;
return {
reload: function(options){
that.config = $.extend({}, that.config, options);
that.render();
}
,val: function(valueArr){
setValue(options, valueArr);
}
,config: options
};
}
,Class = function(options){
var that = this;
that.index = ++regionCheckBox.index;
that.config = $.extend({}, that.config, regionCheckBox.config, options);
that.render();
};
Class.prototype.config = {
data: []
,all: ['所有地域', '所有地域']
,value: []
,width: '550px'
,border: true
,change: function(result){}
,ready: function(){}
};
Class.prototype.render = function(){
var that = this
,options = that.config;
options.elem = $(options.elem);
var id = options.elem.attr('id');
if(!options.elem.hasClass('layui-form')){
options.elem.addClass('layui-form');
}
options.elem.addClass(ELEM_CLASS);
options.elem.css('width', options.width);
if(!options.border){
options.elem.css('border', 'none');
}
options.elem.attr('lay-filter', 'region-' + id);
options.elem.html(getCheckBoxs(options));
//初始值
setValue(options, options.value);
options.elem.find('.parent').mouseover(function() {
$(this).find('.city').show();
});
options.elem.find('.parent').mouseout(function() {
$(this).find('.city').hide();
});
form.on('checkbox(regionCheckBox-'+id+')', function(data) {
if($(data.elem).parents('.all').length > 0) { //选择全部
if(data.elem.checked) {
options.elem.find(':checkbox').prop('checked', true);
} else {
options.elem.find(':checkbox').prop('checked', false);
}
} else {
//选择省(不包括直辖市)
if($(data.elem).parent().hasClass('parent')) {
if(data.elem.checked) {
$(data.elem).parent().find('.city :checkbox').prop('checked', true);
} else {
$(data.elem).parent().find('.city :checkbox').prop('checked', false);
}
}
//选择城市
if($(data.elem).parent().hasClass('city')) {
$(data.elem).parents('.parent').attr('name', options.name);
if(data.elem.checked) {
var is_all = true;
$(data.elem).parent().find(':checkbox').each(function(i, item) {
if(! item.checked) {
is_all = false;
return false;
}
});
if(is_all) {
$(data.elem).parents('.parent').find(':checkbox:first').prop('checked', true);
}
} else {
$(data.elem).parents('.parent').find(':checkbox:first').prop('checked', false);
}
}
//选择除全部外任意
if(data.elem.checked) {
var is_all = true;
options.elem.find('.province :checkbox').each(function(i, item) {
if(! item.checked) {
is_all = false;
return false;
}
});
if(is_all) {
options.elem.find('.all :checkbox').prop('checked', true);
}
} else {
options.elem.find('.all :checkbox').prop('checked', false);
}
}
form.render('checkbox', options.elem.attr('lay-filter'));
renderParentDom(options.elem);
initName(options);
options.change(data);
});
options.ready();
}
function getCheckBoxs(options){
var data = options.data,
all = options.all,
name = options.name,
id = options.elem.attr('id'),
skin = 'primary',
filter = 'regionCheckBox-' + id,
boxs = '',
hasArea = true;
if(all != null && all.length == 2){
boxs = '<div class="layui-form-item all">' +
'<input type="checkbox" name="' + name + '" value="' + all[0] + '" title="' + all[1] + '" lay-skin="' + skin + '" lay-filter="' + filter + '">' +
'</div>' + boxs;
}
if(data[0].TYPE == 'province'){
hasArea = false;
}
if(!hasArea){
boxs += '<div class="layui-form-item" style="margin-bottom: 0;">' +
'<div class="province">' +
'<ul>';
}
for(var i=0; i<data.length; i++){
var area = data[i];
if(area.TYPE == 'area'){
boxs += '<div class="layui-form-item area">' +
'<label class="layui-form-label">' + area.TITLE + '</label>' +
'<div class="province">' +
'<ul>';
var provinceList = area.CHILDREN;
for(var j=0; j<provinceList.length; j++){
boxs += getProvinceLi(provinceList[j], options);
}
boxs += '</ul></div></div>';
}else if(area.TYPE == 'province'){
boxs += getProvinceLi(area, options);
}
}
if(!hasArea){
boxs += '</ul></div>';
}
return boxs;
}
function getProvinceLi(province, options){
var name = options.name,
id = options.elem.attr('id'),
skin = 'primary',
filter = 'regionCheckBox-' + id,
li = '';
var cityList = province.CHILDREN;
var city_num = cityList == null ? 0 : cityList.length;
li += '<li' + (city_num > 0 ? ' class="parent"' : '') + '>' +
'<input type="checkbox" name="' + name + '" value="' + province.VALUE + '" title="' + province.TITLE + '" lay-skin="' + skin + '" lay-filter="' + filter + '">';
if(city_num > 0){
li += '<div class="city">';
for(var k=0; k<city_num; k++){
var city = cityList[k];
li += '<input type="checkbox" name="' + name + '" value="' + city.VALUE + '" title="' + city.TITLE + '" lay-skin="' + skin + '" lay-filter="' + filter + '">';
}
li += '</div>';
}
li += '</li>';
return li;
}
function setValue(options, valueArr){
options.elem.find(':checkbox').prop('checked', false);
var all_value = options.elem.find('.all :checkbox').val();
if(valueArr.indexOf(all_value) > -1){
options.elem.find(':checkbox').prop('checked', true);
}else{
if(typeof valueArr == 'string'){
valueArr = valueArr.split(',');
}
for(var i=0; i<valueArr.length; i++){
var value = valueArr[i]
,$elem = options.elem.find(':checkbox[value="'+value+'"]');
$elem.prop('checked', true);
if(value.indexOf('-') < 0){ //省
$elem.parent().find('.city :checkbox').prop('checked', true);
}
}
}
form.render('checkbox', options.elem.attr('lay-filter'));
renderParentDom(options.elem);
initName(options);
}
function initName(options){
var $elem = options.elem;
$elem.find(':checkbox').attr('name', options.name);
if($elem.find('.all :checkbox').prop('checked')){
$elem.find('.province :checkbox').removeAttr('name');
}else{
$elem.find('.parent').find(':checkbox:first:checked').each(function() {
$(this).parent().find('.city :checkbox').removeAttr('name');
});
}
}
function renderParentDom(elem){
elem.find('.parent').find(':checkbox:first').not(':checked').each(function() {
var is_yes_all = true;
var is_no_all = true;
$(this).parent().find('.city :checkbox').each(function(i, item) {
if(item.checked) {
is_no_all = false;
} else {
is_yes_all = false;
}
});
if(!is_yes_all && !is_no_all) {
$(this).parent().find('.layui-icon:first').removeClass('layui-icon-ok');
$(this).parent().find('.layui-icon:first').css('border-color', '#5FB878');
$(this).parent().find('.layui-icon:first').css('background-color', '#5FB878');
}
});
}
regionCheckBox.render = function(options){
var ins = new Class(options);
return thisIns.call(ins);
};
exports('regionCheckBox', regionCheckBox);
}).link(layui.cache.base+"regionCheckBox/regionCheckBox.css?v="+(new Date).getTime());
+291
View File
@@ -0,0 +1,291 @@
/*
* @version: 2.0
* @Author: tomato
* @Date: 2018-5-5 11:29:57
* @Last Modified by: tomato
* @Last Modified time: 2018-5-26 18:08:43
*/
//多选下拉框
layui.define(['jquery', 'layer'], function(exports){
var MOD_NAME = 'selectM';
var $ = layui.jquery,layer=layui.layer;
var obj = function(config){
this.disabledIndex =[];
//当前选中的值名数据
this.selected = [];
//当前选中的值
this.values =[];
//当前选中的名称
this.names =[];
//初始化设置参数
this.config = {
//选择器id或class
elem: '',
//候选项数据[{id:"1",name:"名称1",status:0},{id:"2",name:"名称2",status:1}]
data: [],
//默认选中值
selected: [],
//空值项提示,支持将{max}替换为max
tips: '请选择 最多 {max} 个',
//最多选中个数,默认5
max : 5,
//选择框宽度
width:null,
//值验证,与lay-verify一致
verify: '',
//input的name 不设置与选择器相同(去#.)
name: '',
//值的分隔符
delimiter: ',',
//候选项数据的键名 status=0为禁用状态
field: {idName:'id',titleName:'name',statusName:'status'}
}
this.config = $.extend(this.config,config);
//创建选项元素
this.createOption = function(){
var o=this,c=o.config,f=c.field,d = c.data;
var s = c.selected;
$E = $(c.elem);
var tips = c.tips.replace('{max}',c.max);
var inputName = c.name=='' ? c.elem.replace('#','').replace('.','') : c.name;
var verify = c.verify=='' ? '' : 'lay-verify="'+c.verify+'" ';
var html = '';
html += '<div class="layui-unselect layui-form-select">';
html += '<div class="layui-select-title">';
html += '<input '+verify+'name="'+inputName+'" type="text" readonly="" class="layui-input layui-unselect">';
html += '</div>';
html += '<div class="layui-input multiple">';
html += '</div>';
html += '<dl class="layui-anim layui-anim-upbit">';
html += '<dd lay-value="" class="layui-select-tips">'+tips+'</dd>';
for(var i=0;i<d.length;i++){
var disabled1='',disabled2='';
if(d[i][f.statusName]==0){
o.disabledIndex[d[i][f.idName]] = d[i][f.titleName];
disabled1 = d[i][f.statusName]==0 ? 'layui-disabled' : '';
disabled2 = d[i][f.statusName]==0 ? ' layui-checkbox-disbaled layui-disabled' : '';
}
html +='<dd lay-value="'+d[i][f.idName]+'" class="'+disabled1+'">';
html += '<div class="layui-unselect layui-form-checkbox'+disabled2+'" lay-skin="primary">';
html += '<span>'+d[i][f.titleName]+'</span><i class="layui-icon">&#xe605;</i>';
html += '</div>';
html +='</dd>';
}
html += '</dl>';
html += '</div>';
$E.html(html);
}
//设置选中值
this.set = function(selected){
var o=this,c=o.config;
var s = typeof selected=='undefined' ? c.selected : selected;
$E = $(c.elem);
$E.find('.layui-form-checkbox').removeClass('layui-form-checked');
$E.find('dd').removeClass('layui-this');
//为默认选中值添加类名
var max = s.length>c.max ? c.max : s.length;
for(var i=0;i<max;i++){
if(s[i] && !o.disabledIndex.hasOwnProperty(s[i])){
$E.find('dd[lay-value='+s[i]+']').addClass('layui-this');
}
}
$E.find('dd.layui-this').each(function(){
$(this).find('div').addClass('layui-form-checked');
});
o.setSelected(selected);
}
this.redata=function(data){
this.config.data = data;
this.createOption();
}
//设置选中值 每次点击操作后执行
this.setSelected = function(first){
var o=this,c=o.config,f=c.field;
$E = $(c.elem);
var values=[],names=[],selected = [],spans = [];
var items = $E.find('dd.layui-this');
if(items.length==0){
var tips = c.tips.replace('{max}',c.max);
spans.push('<span class="tips">'+tips+'</span>');
}
else{
items.each(function(){
$this = $(this);
var item ={};
var v = $this.attr('lay-value');
var n = $this.find('span').text();
item[f.idName] = v;
item[f.titleName] = n;
values.push(v);
names.push(n);
spans.push('<a href="javascript:;"><span lay-value="'+v+'">'+n+'</span><i class="layui-icon">&#x1006;</i></a>');
selected.push(item);
});
}
spans.push('<i class="layui-edge" style="pointer-events: none;"></i>');
$E.find('.multiple').html(spans.join(''));
$E.find('.layui-select-title').find('input').each(function(){
if(typeof first=='undefined'){
this.defaultValue = values.join(c.delimiter);
}
this.value = values.join(c.delimiter);
});
var h = $E.find('.multiple').height()+14;
$E.find('.layui-form-select dl').css('top',h+'px');
o.values=values,o.names=names,o.selected = selected;
}
//ajax方式获取候选数据
this.getData = function(url){
var d;
$.ajax({
url:url,
dataType:'json',
async:false,
success:function(json){
d=json;
},
error: function(){
console.error(MOD_NAME+' hint:候选数据ajax请求错误 ');
d = false;
}
});
return d;
}
};
//渲染一个实例
obj.prototype.render = function(){
var o=this,c=o.config,f=c.field;
$E = $(c.elem);
if($E.length==0){
console.error(MOD_NAME+' hint:找不到容器 ' +c.elem);
return false;
}
if(Object.prototype.toString.call(c.data)!='[object Array]'){
var data = o.getData(c.data);
if(data===false){
console.error(MOD_NAME+' hint:缺少分类数据');
return false;
}
o.config.data = data;
}
//给容器添加一个类名
$E.addClass('lay-ext-mulitsel');
if(/^\d+$/.test(c.width)){
$E.css('width',c.width+'px');
}
//添加专属的style
if($('#lay-ext-mulitsel-style').length==0){
var style = '.lay-ext-mulitsel .layui-form-select dl dd div{margin-top:0px!important;}.lay-ext-mulitsel .layui-form-select dl dd.layui-this{background-color:#fff}.lay-ext-mulitsel .layui-input.multiple{line-height:auto;height:auto;padding:4px 10px 4px 10px;overflow:hidden;min-height:38px;margin-top:-38px;left:0;z-index:99;position:relative;background:#fff;}.lay-ext-mulitsel .layui-input.multiple a{padding:2px 5px;background:#5FB878;border-radius:2px;color:#fff;display:block;line-height:20px;height:20px;margin:2px 5px 2px 0;float:left;}.lay-ext-mulitsel .layui-input.multiple a i{margin-left:4px;font-size:14px;} .lay-ext-mulitsel .layui-input.multiple a i:hover{background-color:#009E94;border-radius:2px;}.lay-ext-mulitsel .danger{border-color:#FF5722!important}.lay-ext-mulitsel .tips{pointer-events: none;position: absolute;left: 10px;top: 10px;color:#757575;}';
$('<style id="lay-ext-mulitsel-style"></style>').text(style).appendTo($('head'));
};
//创建选项
o.createOption();
//设置选中值
o.set();
//展开/收起选项
$E.on('click','.layui-select-title,.multiple,.multiple.layui-edge',function(e){
//隐藏其他实例显示的弹层
$('.lay-ext-mulitsel').not(c.elem).removeClass('layui-form-selected');
if($(c.elem).is('.layui-form-selected')){
$(c.elem).removeClass('layui-form-selected');
$(document).off('click',mEvent);
}
else{
$(c.elem).addClass('layui-form-selected');
$(document).on('click',mEvent=function(e){
if(e.target.id!==c.elem && e.target.className!=='layui-input multiple'){
$(c.elem).removeClass('layui-form-selected');
$(document).off('click',mEvent);
}
});
}
});
//点击选项
$E.on('click','dd',function(e){
var _dd = $(this);
if(_dd.hasClass('layui-disabled')){
return false;
}
//点 请选择
if(_dd.is('.layui-select-tips')){
_dd.siblings().removeClass('layui-this');
$(c.elem).find('.layui-form-checkbox').removeClass('layui-form-checked');
}
//取消选中
else if(_dd.is('.layui-this')){
_dd.removeClass('layui-this');
_dd.find('.layui-form-checkbox').removeClass('layui-form-checked');
e.stopPropagation();
}
//选中
else{
if(o.selected.length >= c.max){
$(c.elem+' .multiple').addClass('danger');
layer.tips('最多只能选择 '+c.max+' 个', c.elem+' .multiple', {
tips: 3,
time: 1000,
end:function(){
$(c.elem+' .multiple').removeClass('danger');
}
});
return false;
}
else{
_dd.addClass('layui-this');
_dd.find('.layui-form-checkbox').addClass('layui-form-checked');
e.stopPropagation();
}
}
o.setSelected();
});
//删除选项
$E.on('click','a i',function(e){
var _this = $(this).prev('span');
var v = _this.attr('lay-value');
if(v){
var _dd = $(c.elem).find('dd[lay-value='+v+']');
_dd.removeClass('layui-this');
_dd.find('.layui-form-checkbox').removeClass('layui-form-checked');
}
o.setSelected();
_this.parent().remove();
e.stopPropagation();
});
//验证失败样式
$E.find('input').focus(function(){
$(c.elem+' .multiple').addClass('danger');
setTimeout(function(){
$(c.elem+' .multiple').removeClass('danger');
},3000);
});
}
//输出模块
exports(MOD_NAME, function (config) {
var _this = new obj(config);
_this.render();
return _this;
});
});
+279
View File
@@ -0,0 +1,279 @@
/*
* @version: 1.2
* @Author: tomato
* @Date: 2018-4-24 22:56:00
* @Last Modified by: tomato
* @Last Modified time: 2018-5-26 18:08:43
*/
//无限级下拉框
layui.define(['jquery', 'form'], function(exports){
var MOD_NAME = 'selectN';
var $ = layui.jquery;
var form = layui.form;
var obj = function(config){
//当前选中数据值名数据
this.selected =[];
//当前选中的值
this.values = [];
//当前选中的名
this.names = [];
//当前选中最后一个值
this.lastValue = '';
//当前选中最后一个值
this.lastName = '';
//是否已选
this.isSelected = false;
//初始化配置
this.config = {
//选择器id或class
elem: '',
//无限级分类数据
data: [],
//默认选中值
selected: [],
//空值项提示,可设置为数组['请选择省','请选择市','请选择县']
tips: '请选择',
//是否允许搜索,可设置为数组[true,true,true]
search:false,
//选择项宽度,可设置为数组['80','90','100']
width:null,
//为真只取最后一个值
last: false,
//值验证,与lay-verify一致
verify: '',
//事件过滤器,lay-filter名
filter: '',
//input的name 不设置与选择器相同(去#.)
name: '',
//数据分隔符
delimiter: ',',
//数据的键名 status=0为禁用状态
field:{idName:'id',titleName:'name',statusName:'status',childName:'children'},
//多表单区分 form.render(type, filter); 为class="layui-form" 所在元素的 lay-filter="" 的值
formFilter: null
}
//实例化配置
this.config = $.extend(this.config,config);
//“请选择”文字
this.setTips = function(){
var o = this,c = o.config;
if(Object.prototype.toString.call(c.tips)!='[object Array]'){
return c.tips;
}
else{
var i=$(c.elem).find('select').length;
return c.tips.hasOwnProperty(i) ? c.tips[i] : '请选择';
}
}
//设置是否允许搜索
this.setSearch = function(){
var o = this,c = o.config;
if(Object.prototype.toString.call(c.search)!='[object Array]'){
return c.search===true ? 'lay-search ' : ' ';
}
else{
var i=$(c.elem).find('select').length;
if(c.search.hasOwnProperty(i)){
return c.search[i]===true ? 'lay-search ' : ' ';
}
}
return ' ';
}
//设置是否允许搜索
this.setWidth = function(){
var o = this,c = o.config;
if(Object.prototype.toString.call(c.width)!='[object Array]'){
return /^\d+$/.test(c.width) ? 'style="width:'+c.width+'px;" ' : ' ';
}
else{
var i=$(c.elem).find('select').length;
if(c.width.hasOwnProperty(i)){
return /^\d+$/.test(c.width[i]) ? 'style="width:'+c.width[i]+'px;" ' : ' ';
}
}
}
//创建一个Select
this.createSelect = function(optionData){
var o = this,c = o.config,f=c.field;
var html = '';
html+= '<div class="layui-input-inline" '+o.setWidth()+'>';
html+= ' <select '+o.setSearch()+'lay-filter="'+c.filter+'">';
html+= ' <option value="">'+o.setTips()+'</option>';
for(var i=0;i<optionData.length;i++){
var disabled = optionData[i][f.statusName]==0 ? 'disabled="" ' : '';
html+= ' <option '+disabled+'value="'+optionData[i][f.idName]+'">'+optionData[i][f.titleName]+'</option>';
}
html+= ' </select>';
html+= '</div>';
return html;
};
//获取当前option的数据
this.getOptionData=function(catData,optionIndex){
var f = this.config.field;
var item = catData;
for(var i=0;i<optionIndex.length;i++){
if('undefined' == typeof item[optionIndex[i]]){
item = null;
break;
}
else if('undefined' == typeof item[optionIndex[i]][f.childName]){
item = null;
break;
}
else{
item = item[optionIndex[i]][f.childName];
}
}
return item;
};
//初始化
this.set = function(selected){
var o = this,c = o.config;
$E = $(c.elem);
//创建顶级select
var verify = c.verify=='' ? '' : 'lay-verify="'+c.verify+'" ';
var html = '<div style="height:0px;width:0px;overflow:hidden"><input '+verify+'name="'+c.name+'"></div>';
html += o.createSelect(c.data);
$E.html(html);
selected = typeof selected=='undefined' ? c.selected : selected;
var index=[];
for(var i=0;i<selected.length;i++){
//设置最后一个select的选中值
$E.find('select:last').val(selected[i]);
//获取该选中值的索引
var lastIndex = $E.find('select:last').get(0).selectedIndex-1;
index.push(lastIndex);
//取出下级的选项值
var childItem = o.getOptionData(c.data,index);
//下级选项值存在则创建select
if(childItem){
var html = o.createSelect(childItem);
$E.append(html);
}
}
form.render('select',c.formFilter);
o.getSelected();
};
//下拉事件
this.change = function(elem){
var o = this,c = o.config;
var $thisItem = elem.parent();
//移除后面的select
$thisItem.nextAll('div.layui-input-inline').remove();
var index=[];
//获取所有select,取出选中项的值和索引
$thisItem.parent().find('select').each(function(){
index.push($(this).get(0).selectedIndex-1);
});
var childItem = o.getOptionData(c.data,index);
if(childItem){
var html = o.createSelect(childItem);
$thisItem.after(html);
form.render('select',c.formFilter);
}
o.getSelected();
};
//获取所有值-数组 每次选择后执行
this.getSelected=function(){
var o = this,c = o.config;
var values =[];
var names =[];
var selected =[];
$E = $(c.elem);
$E.find('select').each(function(){
var item = {};
var v = $(this).val()
var n = $(this).find('option:selected').text();
item.value = v;
item.name = n;
values.push(v);
names.push(n);
selected.push(item);
});
o.selected =selected;
o.values = values;
o.names = names;
o.lastValue = $E.find('select:last').val();
o.lastName = $E.find('option:selected:last').text();
o.isSelected = o.lastValue=='' ? false : true;
var inputVal = c.last===true ? o.lastValue : o.values.join(c.delimiter);
$E.find('input[name="'+c.name+'"]').val(inputVal);
};
//ajax方式获取候选数据
this.getData = function(url){
var d;
$.ajax({
url:url,
dataType:'json',
async:false,
success:function(json){
d=json;
},
error: function(){
console.error(MOD_NAME+' hint:候选数据ajax请求错误 ');
d = false;
}
});
return d;
}
};
//渲染一个实例
obj.prototype.render = function(){
var o=this,c=o.config;
$E = $(c.elem);
if($E.length==0){
console.error(MOD_NAME+' hint:找不到容器 '+c.elem);
return false;
}
if(Object.prototype.toString.call(c.data)!='[object Array]'){
var data = o.getData(c.data);
if(data===false){
console.error(MOD_NAME+' hint:缺少分类数据');
return false;
}
o.config.data = data;
}
c.filter = c.filter=='' ? c.elem.replace('#','').replace('.','') : c.filter;
c.name = c.name=='' ? c.elem.replace('#','').replace('.','') : c.name;
o.config = c;
//初始化
o.set();
//监听下拉事件
form.on('select('+c.filter+')',function(data){
o.change($(data.elem));
});
//验证失败样式
$E.find('input[name="'+c.name+'"]').focus(function(){
var t = $(c.elem).offset().top;
$('html,body').scrollTop(t-200);
$(c.elem).find('select:last').addClass('layui-form-danger');
setTimeout(function(){
$(c.elem).find('select:last').removeClass('layui-form-danger');
},3000);
});
}
//输出模块
exports(MOD_NAME, function (config) {
var _this = new obj(config);
_this.render();
return _this;
});
});
+13
View File
@@ -0,0 +1,13 @@
/* selectY 样式表*/
.selectY-box{position: relative;height: 30px;}
.selectY-box .show{position:relative;height:28px;line-height: 28px;padding:0 25px 0 10px;min-width:30px;display: inline-block;background-color:#fff;cursor: pointer}
.selectY-box .show:after{font-family:'layui-icon'!important;content: "\e602";color:#e6e6e6;position: absolute;top:0;right:5px}
.selectY-box .show i{color:#e6e6e6;padding:0 5px}
.selectY-box .pop{position: absolute;z-index:99;top:29px;left:0;display: none;box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);}
.selectY-box .show,.selectY-box .pop ul{border:1px solid #e6e6e6;}
.selectY-box .pop ul{background-color:#fff;min-width:160px;height:237px;padding:5px 0;float:left;margin-left: -1px;overflow :auto;}
.selectY-box .pop ul:first-child{margin-left:0}
.selectY-box .pop ul li{padding:5px 30px 5px 20px;position: relative;cursor: pointer}
.selectY-box .pop ul li.child-row:after{font-family:'layui-icon'!important;content: "\e602";color:#e6e6e6;position: absolute;top:5px;right:10px}
.selectY-box .pop ul li:hover{background-color:#f8f8f8}
.selectY-box .pop ul li.active{color:red}
+196
View File
@@ -0,0 +1,196 @@
/**
*
* selectY,只需要pid,id,name,就可以无限级选择
selectY({
elem:'#demo',
data:data,
//url为ajax 获取json数据,当url属性有值时,不提取data属性值
//url:'https://cityApi.html',
placeholder:'请选择地址',
disabledTips:'当前区域没有产品',
success:function(e){
console.log(e.data);
console.log(e.ids);
}
});
*
*/
layui.define('layer',function (exports) {
var $ = layui.$, layer = layui.layer;
'use strict';
var P = function(o){
this.c = {
//input type = hidden 的元素
elem:'',
data:'',
url:'',
placeholder:'请选择:',
disabledTips:'',
success:function(){}
//separator: '&nbsp;/&nbsp;'
};
this.c = $.extend(this.c,o);
this.getData = function(url){
var res;
$.ajax({
url:url,
type: "get",
dataType:'json',
async:false,
success:function(e){
res = e.data || layer.msg('数据接口错误,请正确配置');
},
error: function(){
layer.msg('数据接口错误,请正确配置');
res = '';
}
});
return res;
};
//生成树
// this.toTree = function(data,pid){
// var o = this, tree = [], temp;
// for (var i = 0; i < data.length; i++) {
// if (data[i].pid == pid) {
// var obj = data[i];
// temp = o.toTree(data, data[i].id);
// if (temp.length > 0) {
// obj.children = temp;
// }
// tree.push(obj);
// }
// }
// return tree;
// };
this.getChild = function(data,pid){
var child = [];
for (var i = 0; i < data.length; i++) {
if (data[i].pid == pid) {
child.push(data[i]);
}
}
return child;
};
this.createChild = function(items){
var o = this;
var ul = '<ul>';
for(var i = 0; i < items.length; i++){
var row = o.getChild(o.data,items[i].id);
row = row.length != 0 ? 'child-row' : '';
var off = items[i].off ? 'layui-disabled' : '';
ul += '<li class ="'+row+' '+off+'" data-id="'+items[i].id+'">'+items[i].name+'</li>'
}
ul += '</ul>';
return ul;
};
this.setValue = function (value) {
var o = this, data = o.data, itemID = [];
for(var i=0;i<data.length;i++){
for(var j=0;j<value.length;j++){
if(value[j] == data[i].name){
//data[i].checked = true;
itemID.push(data[i].id);
}
}
}
return itemID;
};
this.showPopup = function (data,id) {
var o =this;
var items = o.getChild(data,id);
if(items.length != 0){
var itemsHtml = o.createChild(items);
$(o.c.elem).parent().find('.pop').append(itemsHtml);
}
};
this.scroll = function () {
var o = this, c = o.c, ele = c.elem;
var x = $(ele).parent().find('.pop ul');
for(var j = 0; j < x.length; j ++){
var e = x.eq(j).children('li.active');
if (e[0]) {
var t = e.position().top, i = x.eq(j).height(), a = e.height();
t > i && x.eq(j).scrollTop(t + x.eq(j).scrollTop() - i + a + 3),
t < 0 && x.eq(j).scrollTop(t + x.eq(j).scrollTop() - 5)
}
}
};
this.data = this.c.url ? this.getData(this.c.url) : this.c.data;
}
P.prototype.render = function(){
var o = this, c = o.c, e = c.elem;
var html = '<div class="selectY-box"></div>',
show = '<span class="show"><span class="cl-exp">'+c.placeholder+'</span></span>',
pop = '<div class="pop"></div>';
$(e).wrap(html);
$(e).after(show + pop);
o.showPopup(o.data,0);
if($(e).val()!=''){
var value = $(e).val().split('/');
var showValue = value.join('<i>/</i>');
$(e).parent().find('.show').html(showValue);
var setID = this.setValue(value);
for(var i = 0; i < setID.length; i ++){
o.showPopup(o.data,setID[i]);
var fistUi = $(e).parent().find('.pop ul');
fistUi.eq(i).find('li[data-id='+setID[i]+']').addClass('active');
}
}
$(e).parent().find('.pop').on('click','ul li',function (en) {
if($(this).hasClass("layui-disabled")){
layer.msg(c.disabledTips);
return false;
}
$(this).addClass('active').siblings().removeClass('active');
$(this).parent().nextAll('ul').remove();
var id = $(this).data('id');
o.showPopup(o.data,id);
if(!$(this).hasClass("child-row")){
$(e).parent().find('.pop').hide();
var activeLi = $(e).parent().find('.pop li.active');
var checkValue = [], ids = [];
for(var i = 0; i < activeLi.length; i ++){
checkValue.push(activeLi.eq(i).html());
ids.push(activeLi.eq(i).data('id'))
}
var inputValue = checkValue.join('/');
var showValue = checkValue.join('<i>/</i>');
$(e).val(inputValue);
$(e).parent().find('.show').html(showValue);
//回调函数
if (typeof c.success === "function") {
var callback = {
//数据name 如安徽省/合肥市/蜀山区
data:inputValue,
//数据ID数组,如1,8,16
ids:ids
};
c.success(callback);
}
}
layui.stope(en);
});
$(e).parent().find('.show').on('click',function(en){
//if()
$(e).parent().find('.pop').show();
o.scroll();
layui.stope(en);
})
$(document).on('click',function(){
$(e).parent().find('.pop').hide();
})
}
exports('selectY', function(o){
var t = new P(o);
t.render();
});
}).link(layui.cache.base+"selectY/selectY.css?v="+(new Date).getTime());
+233
View File
@@ -0,0 +1,233 @@
layui.define('layer', function(exports) {
var $ = layui.$, layer = layui.layer;
'use strict';
var SelectY2 = function(o) {
this.c = {
elem: '',
data: '',
url: '',
placeholder: '请选择:',
disabledTips: '',
success: function() {}
};
this.c = $.extend(this.c, o);
this.init();
};
SelectY2.prototype = {
init: function() {
this.data = this.c.url ? this.getData(this.c.url) : this.c.data;
this.render();
},
getData: function(url) {
var res;
$.ajax({
url: url,
type: "get",
dataType: 'json',
async: false,
success: function(e) {
res = e.data || layer.msg('数据接口错误,请正确配置');
},
error: function() {
layer.msg('数据接口错误,请正确配置');
res = '';
}
});
return res;
},
getChild: function(data, pid) {
var child = [];
for (var i = 0; i < data.length; i++) {
if (data[i].pid == pid) {
child.push(data[i]);
}
}
return child;
},
createChild: function(items) {
var o = this;
var ul = '<ul>';
for (var i = 0; i < items.length; i++) {
var row = o.getChild(o.data, items[i].id);
row = row.length != 0 ? 'child-row' : '';
var off = items[i].off ? 'layui-disabled' : '';
ul += '<li class="' + row + ' ' + off + '" data-id="' + items[i].id + '">' + items[i].name + '</li>';
}
ul += '</ul>';
return ul;
},
setValue: function(value) {
var o = this, data = o.data;
var elem = $(o.c.elem);
var parent = elem.parent();
// 清空当前选中状态和弹出层内容
parent.find('.pop').empty();
parent.find('.show').html(o.c.placeholder);
elem.val('');
// 查找匹配的值路径
var path = [];
var currentItems = o.getChild(data, 0); // 从顶级开始
for (var i = 0; i < value.length; i++) {
var found = false;
for (var j = 0; j < currentItems.length; j++) {
if (currentItems[j].name === value[i]) {
path.push(currentItems[j]);
currentItems = o.getChild(data, currentItems[j].id);
found = true;
break;
}
}
if (!found) {
break; // 如果没找到匹配项,中断循环
}
}
if (path.length > 0) {
// 重建弹出层结构
parent.find('.pop').empty();
for (var k = 0; k < path.length; k++) {
var items = o.getChild(data, k === 0 ? 0 : path[k-1].id);
var itemsHtml = o.createChild(items);
parent.find('.pop').append(itemsHtml);
// 激活当前层级的选择项
var currentUl = parent.find('.pop ul').eq(k);
currentUl.find('li[data-id="' + path[k].id + '"]').addClass('active');
}
// 添加下一级(如果有)
var lastItem = path[path.length - 1];
var childItems = o.getChild(data, lastItem.id);
if (childItems.length > 0) {
var childHtml = o.createChild(childItems);
parent.find('.pop').append(childHtml);
}
// 更新显示值和输入框值
var showValue = path.map(function(item) { return item.name; }).join('<i>/</i>');
var inputValue = path.map(function(item) { return item.name; }).join('/');
parent.find('.show').html(showValue);
elem.val(inputValue);
// 调用成功回调
if (typeof o.c.success === "function") {
var ids = path.map(function(item) { return item.id; });
var vvv = path.map(function(item){return item.name;});
o.c.success({
data: vvv,
ids: ids
});
}
// 返回 ID 数组(关键修改)
return path.map(function(item) { return item.id; });
}
return []; // 如果没有匹配项,返回空数组
},
showPopup: function(data, id) {
var o = this;
var items = o.getChild(data, id);
if (items.length != 0) {
var itemsHtml = o.createChild(items);
$(o.c.elem).parent().find('.pop').append(itemsHtml);
}
},
scroll: function() {
var o = this, c = o.c, ele = c.elem;
var x = $(ele).parent().find('.pop ul');
for (var j = 0; j < x.length; j++) {
var e = x.eq(j).children('li.active');
if (e[0]) {
var t = e.position().top, i = x.eq(j).height(), a = e.height();
t > i && x.eq(j).scrollTop(t + x.eq(j).scrollTop() - i + a + 3),
t < 0 && x.eq(j).scrollTop(t + x.eq(j).scrollTop() - 5)
}
}
},
render: function() {
var o = this, c = o.c, e = c.elem;
var html = '<div class="selectY-box"></div>',
show = '<span class="show"><span class="cl-exp">' + c.placeholder + '</span></span>',
pop = '<div class="pop"></div>';
$(e).wrap(html);
$(e).after(show + pop);
o.showPopup(o.data, 0);
if ($(e).val() != '') {
var value = $(e).val().split('/');
var showValue = value.join('<i>/</i>');
$(e).parent().find('.show').html(showValue);
// 获取 setValue 返回的 ID 数组
var setID = o.setValue(value);
for (var i = 0; i < setID.length; i++) {
o.showPopup(o.data, setID[i]);
var fistUi = $(e).parent().find('.pop ul');
fistUi.eq(i).find('li[data-id=' + setID[i] + ']').addClass('active');
}
}
$(e).parent().find('.pop').on('click', 'ul li', function(en) {
if ($(this).hasClass("layui-disabled")) {
layer.msg(c.disabledTips);
return false;
}
$(this).addClass('active').siblings().removeClass('active');
$(this).parent().nextAll('ul').remove();
var id = $(this).data('id');
o.showPopup(o.data, id);
if (!$(this).hasClass("child-row")) {
$(e).parent().find('.pop').hide();
var activeLi = $(e).parent().find('.pop li.active');
var checkValue = [], ids = [];
for (var i = 0; i < activeLi.length; i++) {
checkValue.push(activeLi.eq(i).html());
ids.push(activeLi.eq(i).data('id'))
}
var inputValue = checkValue.join('/');
var showValue = checkValue.join('<i>/</i>');
$(e).val(inputValue);
$(e).parent().find('.show').html(showValue);
if (typeof c.success === "function") {
var callback = {
data: checkValue,
ids: ids
};
c.success(callback);
}
}
layui.stope(en);
});
$(e).parent().find('.show').on('click', function(en) {
$(e).parent().find('.pop').show();
o.scroll();
layui.stope(en);
});
$(document).on('click', function() {
$(e).parent().find('.pop').hide();
});
}
};
exports('selectY2', function(o) {
return new SelectY2(o);
});
}).link(layui.cache.base + "selectY/selectY.css?v=" + (new Date).getTime());
@@ -0,0 +1,168 @@
@charset "UTF-8";
/*sliderTime*/
.layui-slider-bar-selected {
position: absolute;
background-color: #696969;
height: 100%;
z-index: 1;
}
.step-hour {
height: 20px !important;
width: 1px !important;
top: -16px !important;
}
.step-half-hour {
height: 10px !important;
width: 1px !important;
top: -6px !important;
}
.step-hour,
.step-half-hour,
.step-start-wrap,
.step-end-wrap {
border-radius: 0;
border-radius: unset;
}
.layui-slider-step {
border-radius: 0;
height: 6px;
width: 1px;
top: -2px;
}
.layui-slider-bar {
z-index: 1;
}
.step-start-num {
position: absolute;
left: -18px;
top: 8px;
}
.step-end-num {
position: absolute;
right: -15px;
top: 6px;
}
.step-start-wrap {
position: absolute;
left: 0px;
top: -16px;
height: 20px;
width: 2px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.step-end-wrap {
position: absolute;
right: -2px;
top: -16px;
height: 20px;
width: 2px;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.slider-danger-tips {
position: absolute;
top: 12px;
z-index: 66666666;
white-space: nowrap;
display: none;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
border-radius: 3px;
height: 25px;
line-height: 25px;
padding: 0 10px;
}
.layui-disabled .step-hour, .layui-disabled .step-half-hour, .layui-disabled .step-start-wrap, .layui-disabled .step-end-wrap, .layui-disabled .layui-slider-step {
background: #696969;
}
/*垂直*/
.layui-slider-vertical .step-start-num {
left: -16px;
top: inherit;
top: unset;
bottom: -22px;
}
.layui-slider-vertical .step-end-num {
top: -22px;
right: inherit;
right: unset;
left: -16px;
}
.layui-slider-vertical .step-start-wrap {
height: 2px;
width: 20px;
bottom: 0;
top: inherit;
top: unset;
left: 10px;
}
.layui-slider-vertical .step-end-wrap {
height: 2px;
width: 20px;
right: inherit;
right: unset;
left: 10px;
top: 0;
}
.layui-slider-vertical .step-hour {
height: 1px !important;
width: 20px !important;
top: inherit !important;
top: unset !important;
}
.layui-slider-vertical .step-half-hour{
height: 1px !important;
width: 10px !important;
top: inherit !important;
top: unset !important;
}
.layui-slider-vertical .layui-slider-step{
height: 1px;
width: 4px;
}
.layui-slider-vertical .layui-slider-bar-selected{
width: 4px;
bottom: 150px;
height: 37.5%;
}
.layui-slider-vertical .slider-danger-tips{
top: inherit;
top: unset;
left: 100px;
}
/*主题颜色*/
.step-hour,
.step-half-hour,
.step-start-wrap,
.step-end-wrap {
background: #009688
}
.layui-slider-step {
background: #00bfb1;
}
.slider-danger-tips {
color: #FFF;
background: #FF5722;
}
@@ -0,0 +1,327 @@
/**
* 时间范围滑块选择插件
* 基于 layui.slider 扩展的时间范围选择插件
*
* sliderTime.js License By momo
* V1.0 2021-04-19
*
*
* 使用说明:
* 1.sliderTime 基于 layui.slider,所以 slider 的配置都得以保留
* 2.range 参数强制为 true
* 3.新增 disabledValue 属性,禁止选择时间范围
* 例如:[[8:00, 10:00], [14:00, 15:00]]
* 4.新增 disabledText 属性,禁止选择时间范围被选中后的提示内容,不配置不显示提示
* 例如:'{start} - {end} 已占用',支持start和end时间占位符
* 5.新增 getValue 方法,返回当前选择的时间段(时间格式)
* 6.新增 isOccupation 方法,返回当前选择的时间段是否包含了禁止选择的时间段
* 7.新增 numToTime 公用方法,用于将十进制转为时间格式。例如:480 → 08:00
* 8.新增 timeToNum 公用方法,用于将时间格式转为十进制。例如:24:00 → 1440
*/
layui.define(['slider'], function (exports) {
"use strict";
var MOD_NAME = 'sliderTime',
$ = layui.jquery,
slider = layui.slider;
;
/**
* 外部接口
*/
var SliderTime = {
config: {}
/**
* 核心入口
*/
, render: function (options) {
var object = new Class(options);
return thisSliderTime.call(object);
}
/**
* 数字转时间格式
*/
, numToTime: function (value) {
var hours = Math.floor(value / 60);
var mins = (value - hours * 60);
return (hours < 10 ? "0" + hours : hours) + ":" + (mins < 10 ? "0" + mins : mins);
}
/**
* 时间转数字
*/
, timeToNum: function (value) {
var time = value.split(":");
return time[0] * 60 + parseInt(time[1]);
}
};
/**
* 构造器
*/
var Class = function (options) {
var that = this;
that.config = $.extend({}, SliderTime.config, options);
that.render();
};
/**
* 操作当前实例
*/
var thisSliderTime = function () {
var that = this
, options = that.config;
return {
/**
* 设置时间段
*/
setValue: function (value, index) {
if (index !== 1) {
index = 0;
}
value = SliderTime.timeToNum(value);
var start, end, width,
$wrap = $(options.elem).find('.layui-slider-wrap'),
val = [$wrap.eq(0).data("value"), $wrap.eq(1).data("value")];
if (value === val[0] || value === val[1]) {
// 设置值等于当前最小或最大值,不移动
return;
} else if (value > val[1]) {
// 设置值大于当前最大值,移动后面圆点
val[1] > val[0] ? index = 1 : index = 0;
val[index] = value;
} else if (value < val[0]) {
// 设置值小于当前最小值,移动前面圆点
val[0] < val[1] ? index = 0 : index = 1;
val[index] = value;
} else {
// 设置值间与中间,则按照index移动
index === 0 ? val[0] = value : val[1] = value;
}
$wrap.eq(index).data("value", value);
start = (val[0] - options.min) / (options.max - options.min) * 100;
end = (val[1] - options.min) / (options.max - options.min) * 100;
// 设置圆点位置
if ("vertical" === options.type) {
$(options.elem).find('.layui-slider-wrap').eq(index).css("bottom", (index === 0 ? start : end) + '%');
} else {
$(options.elem).find('.layui-slider-wrap').eq(index).css("left", (index === 0 ? start : end) + '%');
}
// 设置滑动位置
width = Math.abs(end - start);
if ("vertical" === options.type) {
$(options.elem).find('.layui-slider-bar').css({
"height": width + '%',
"bottom": (start < end ? start : end) + '%'
});
} else {
$(options.elem).find('.layui-slider-bar').css({
"width": width + '%',
"left": (start < end ? start : end) + '%'
});
}
return;
// return that.slider.setValue(SliderTime.timeToNum(value), index)
}
/**
* 获取选中的时间段
*/
, getValue: function () {
var $wrap = $(options.elem).find('.layui-slider-wrap');
var value = [$wrap.eq(0).data("value"), $wrap.eq(1).data("value")];
//如果前面的圆点超过了后面的圆点值,则调换顺序
if (value[0] > value[1]) {
value.reverse();
}
return [SliderTime.numToTime(value[0]), SliderTime.numToTime(value[1])];
}
/**
* 选择的时间段是否包含被禁止选择的时间段
* 包含:返回禁止选择的时间段
* 不包含:false
*/
, isOccupation: function () {
if (options.disabledValue) {
var $wrap = $(options.elem).find('.layui-slider-wrap');
var value = [$wrap.eq(0).data("value"), $wrap.eq(1).data("value")];
//如果前面的圆点超过了后面的圆点值,则调换顺序
if (value[0] > value[1]) {
value.reverse();
}
for (var i in options.disabledValue) {
var date = options.disabledValue[i];
var min = SliderTime.timeToNum(date[0]);
var max = SliderTime.timeToNum(date[1]);
if (value[0] > min && value[0] < max
|| value[1] > min && value[1] < max
|| value[0] <= min && value[1] >= max) {
return date;
} else {
that.closeTips(options.elem);
}
}
return false;
} else {
return false;
}
}
, config: options
}
};
/**
* 滑块渲染
* @param options
*/
Class.prototype.render = function () {
var that = this
, options = that.config;
// 是否显示时刻,默认是
options.showstep = options.showstep == false ? false : true;
// 开启滑块的范围拖拽
options.range = true;
// 最小值,最小为0=0:00
options.min = options.min == undefined || SliderTime.timeToNum(options.min) < 0 ? 0 : SliderTime.timeToNum(options.min);
// 最大值,最大为1440=24*60=24:00
options.max = options.max == undefined || SliderTime.timeToNum(options.max);
// options.max = options.max == undefined || SliderTime.timeToNum(options.max) > 1440 ? 1440 : SliderTime.timeToNum(options.max);
//间隔值不能大于 max
options.step = options.step > options.max ? options.max : options.step;
// 初始值
options.value = typeof (options.value) == 'object' ? options.value : [SliderTime.numToTime(options.min), SliderTime.numToTime(options.min)];
options.value[0] = SliderTime.timeToNum(options.value[0]);
options.value[1] = SliderTime.timeToNum(options.value[1]);
// 初始化
that.slider = slider.render({
elem: options.elem
, type: options.type
, height: options.height
, theme: options.theme
, range: options.range
, showstep: options.showstep
, min: options.min
, max: options.max
, step: options.step
, value: options.value
, disabled: options.disabled
, setTips: function (value) {
value = SliderTime.numToTime(value);
if (options.setTips) {
return options.setTips(value);
} else {
return value;
}
}
, change: function (value) {
if (options.disabledValue && options.disabledText) {
// 当滑动到禁用时间范围时,自动提醒
for (var i in options.disabledValue) {
var date = options.disabledValue[i];
var min = SliderTime.timeToNum(date[0]);
var max = SliderTime.timeToNum(date[1]);
if (value[0] > min && value[0] < max
|| value[1] > min && value[1] < max
|| value[0] <= min && value[1] >= max) {
var disabledText = options.disabledText.replace('{start}', date[0]).replace('{end}', date[1])
that.showTips(options, disabledText)
break;
} else {
that.closeTips(options.elem);
}
}
}
if (options.change) {
options.change(value);
}
}
});
// 扩展元素
$(options.elem).find('.layui-slider')
// 开始结尾刻度时间
.append('<div class="step-start-num">' + SliderTime.numToTime(options.min) + '</div>')
.append('<div class="step-end-num">' + SliderTime.numToTime(options.max) + '</div>')
// 警告提示Tips
.append('<div class="slider-danger-tips"></div>');
if (options.showstep) {
// 开始结尾刻度标识
$(options.elem).find('.layui-slider')
.append('<div class="step-start-wrap"></div>')
.append('<div class="step-end-wrap"></div>');
}
// 定义整点和半点时刻标识
var $steps = $(options.elem).find('.layui-slider .layui-slider-step');
for (var i = 0, num = options.min; num <= options.max && i < $steps.length - 1; i++, num += options.step) {
if (that.numToMins(num) == 0 && i > 0) {
$steps.eq(i - 1).addClass('step-hour');
} else if (that.numToMins(num) == 30) {
$steps.eq(i - 1).addClass('step-half-hour');
}
}
// 初始化选中禁止选择时间范围
if (options.disabledValue) {
options.disabledValue.forEach(function (date) {
var dateNum = [SliderTime.timeToNum(date[0]), SliderTime.timeToNum(date[1])];
var start = (dateNum[0] - options.min) / (options.max - options.min) * 100,
end = (dateNum[1] - options.min) / (options.max - options.min) * 100,
width = end - start;
var selectedSlider = '<div class="layui-slider-bar-selected layui-disabled" style=" ' + ("vertical" === options.type ? "height" : "width") + ':' + width + '%; ' + ("vertical" === options.type ? "bottom" : "left") + ':' + start + '% ;"></div>';
$(options.elem).find('.layui-slider-bar').after(selectedSlider);
});
}
// 主题设置
if (options.theme) {
$(options.elem).find('.step-hour,.step-half-hour,.step-start-wrap,.step-end-wrap,.layui-slider-step').css("background", options.theme);
}
};
/**
* 数字转分钟
*/
Class.prototype.numToMins = function (value) {
var hours = Math.floor(value / 60);
var mins = (value - hours * 60);
return mins;
};
/**
* 显示警告信息
*/
Class.prototype.showTips = function (options, text) {
if ("vertical" === options.type) {
$(options.elem).find('.slider-danger-tips').css({
"display": "block",
"bottom": $(options.elem).find('.layui-slider-tips')[0].style.bottom
}).text(text);
} else {
$(options.elem).find('.slider-danger-tips').css({
"display": "block",
"left": $(options.elem).find('.layui-slider-tips')[0].style.left
}).text(text);
}
};
/**
* 关闭警告信息
*/
Class.prototype.closeTips = function (elem) {
$(elem).find('.slider-danger-tips').css({
"display": "none"
}).text('');
};
// 加载css
layui.link(layui.cache.base + "sliderTime/sliderTime.css?v="+(new Date).getTime());
exports(MOD_NAME, SliderTime);
});
File diff suppressed because one or more lines are too long
+79
View File
@@ -0,0 +1,79 @@
.lay-step {
font-size: 0;
width: 400px;
margin: 0 auto;
max-width: 100%;
padding-left: 200px;
}
.step-item {
display: inline-block;
line-height: 26px;
position: relative;
font-size: 14px;
}
.step-item-tail {
width: 100%;
padding: 0 10px;
position: absolute;
left: 0;
top: 13px;
}
.step-item-tail i {
display: inline-block;
width: 100%;
height: 1px;
vertical-align: top;
background: #c2c2c2;
position: relative;
}
.step-item-tail .step-item-tail-done {
background: #009688;
}
.step-item-head {
position: relative;
display: inline-block;
height: 26px;
width: 26px;
text-align: center;
vertical-align: top;
color: #009688;
border: 1px solid #009688;
border-radius: 50%;
background: #ffffff;
}
.step-item-head.step-item-head-active {
background: #009688;
color: #ffffff;
}
.step-item-main {
display: block;
position: relative;
margin-left: -50%;
margin-right: 50%;
padding-left: 26px;
text-align: center;
}
.step-item-main-title {
font-weight: bolder;
color: #555555;
}
.step-item-main-desc {
color: #aaaaaa;
}
.lay-step + [carousel-item]:before {
display: none;
}
.lay-step + [carousel-item] > * {
background-color: transparent;
}
+101
View File
@@ -0,0 +1,101 @@
layui.define(['layer', 'carousel'], function (exports) {
var $ = layui.jquery;
var layer = layui.layer;
var carousel = layui.carousel;
// 添加步骤条dom节点
var renderDom = function (elem, stepItems, postion) {
var stepDiv = '<div class="lay-step">';
for (var i = 0; i < stepItems.length; i++) {
stepDiv += '<div class="step-item">';
// 线
if (i < (stepItems.length - 1)) {
if (i < postion) {
stepDiv += '<div class="step-item-tail"><i class="step-item-tail-done"></i></div>';
} else {
stepDiv += '<div class="step-item-tail"><i class=""></i></div>';
}
}
// 数字
var number = stepItems[i].number;
if (!number) {
number = i + 1;
}
if (i == postion) {
stepDiv += '<div class="step-item-head step-item-head-active"><i class="layui-icon">' + number + '</i></div>';
} else if (i < postion) {
stepDiv += '<div class="step-item-head"><i class="layui-icon layui-icon-ok"></i></div>';
} else {
stepDiv += '<div class="step-item-head "><i class="layui-icon">' + number + '</i></div>';
}
// 标题和描述
var title = stepItems[i].title;
var desc = stepItems[i].desc;
if (title || desc) {
stepDiv += '<div class="step-item-main">';
if (title) {
stepDiv += '<div class="step-item-main-title">' + title + '</div>';
}
if (desc) {
stepDiv += '<div class="step-item-main-desc">' + desc + '</div>';
}
stepDiv += '</div>';
}
stepDiv += '</div>';
}
stepDiv += '</div>';
$(elem).prepend(stepDiv);
// 计算每一个条目的宽度
var bfb = 100 / stepItems.length;
$('.step-item').css('width', bfb + '%');
};
var step = {
// 渲染步骤条
render: function (param) {
param.indicator = 'none'; // 不显示指示器
param.arrow = 'always'; // 始终显示箭头
param.autoplay = false; // 关闭自动播放
if (!param.stepWidth) {
param.stepWidth = '400px';
}
// 渲染轮播图
carousel.render(param);
// 渲染步骤条
var stepItems = param.stepItems;
renderDom(param.elem, stepItems, 0);
$('.lay-step').css('width', param.stepWidth);
//监听轮播切换事件
carousel.on('change(' + param.filter + ')', function (obj) {
$(param.elem).find('.lay-step').remove();
renderDom(param.elem, stepItems, obj.index);
$('.lay-step').css('width', param.stepWidth);
});
// 隐藏左右箭头按钮
$(param.elem).find('.layui-carousel-arrow').css('display', 'none');
// 去掉轮播图的背景颜色
$(param.elem).css('background-color', 'transparent');
},
// 下一步
next: function (elem) {
$(elem).find('.layui-carousel-arrow[lay-type=add]').trigger('click');
},
// 上一步
pre: function (elem) {
$(elem).find('.layui-carousel-arrow[lay-type=sub]').trigger('click');
}
};
layui.link(layui.cache.base + "step-lay/step.css?v="+(new Date).getTime());
exports('step', step);
});
@@ -0,0 +1,75 @@
/**
* Created by YujieYang.
* @name: 子表格扩展
* @author: 杨玉杰
* @version 1.0
*/
layui.define(['table'], function (exports) {
var $ = layui.jquery;
// 封装方法
var mod = {
/**
* 渲染入口
* @param myTable
*/
render: function (myTable) {
var tableBox = $(myTable.elem).next().children('.layui-table-box'),
$main = $(tableBox.children('.layui-table-body').children('table').children('tbody').children('tr').toArray().reverse()),
$fixLeft = $(tableBox.children('.layui-table-fixed-l').children('.layui-table-body').children('table').children('tbody').children('tr').toArray().reverse()),
$fixRight = $(tableBox.children('.layui-table-fixed-r').children('.layui-table-body').children('table').children('tbody').children('tr').toArray().reverse()),
cols = myTable.cols[0], mergeRecord = {};
for (let i = 0; i < cols.length; i++) {
var item3 = cols[i], field=item3.field;
if (item3.merge) {
var mergeField = [field];
if (item3.merge !== true) {
if (typeof item3.merge == 'string') {
mergeField = [item3.merge]
} else {
mergeField = item3.merge
}
}
mergeRecord[i] = {mergeField: mergeField, rowspan:1}
}
}
$main.each(function (i) {
for (var item in mergeRecord) {
if (i==$main.length-1 || isMaster(i, item)) {
$(this).children('[data-key$="-'+item+'"]').attr('rowspan', mergeRecord[item].rowspan).css('position','static');
$fixLeft.eq(i).children('[data-key$="-'+item+'"]').attr('rowspan', mergeRecord[item].rowspan).css('position','static');
$fixRight.eq(i).children('[data-key$="-'+item+'"]').attr('rowspan', mergeRecord[item].rowspan).css('position','static');
mergeRecord[item].rowspan = 1;
} else {
$(this).children('[data-key$="-'+item+'"]').remove();
$fixLeft.eq(i).children('[data-key$="-'+item+'"]').remove();
$fixRight.eq(i).children('[data-key$="-'+item+'"]').remove();
mergeRecord[item].rowspan +=1;
}
}
})
function isMaster (index, item) {
var mergeField = mergeRecord[item].mergeField;
var dataLength = layui.table.cache[myTable.id].length;
for (var i=0; i<mergeField.length; i++) {
if (layui.table.cache[myTable.id][dataLength-2-index][mergeField[i]]
!== layui.table.cache[myTable.id][dataLength-1-index][mergeField[i]]) {
return true;
}
}
return false;
}
}
};
// 输出
exports('tableMerge', mod);
});
@@ -0,0 +1,260 @@
layui.define(['table', 'jquery', 'form'], function (exports) {
"use strict";
var MOD_NAME = 'tableSelect',
$ = layui.jquery,
table = layui.table,
form = layui.form;
var tableSelect = function () {
this.v = '1.1.0';
};
/**
* 初始化表格选择器
*/
tableSelect.prototype.render = function (opt) {
var elem = $(opt.elem);
var tableDone = opt.table.done || function(){};
//默认设置
opt.searchKey = opt.searchKey || 'keyword';
opt.searchPlaceholder = opt.searchPlaceholder || '关键词搜索';
opt.checkedKey = opt.checkedKey;
opt.table.page = opt.table.page || true;
opt.table.height = opt.table.height || 315;
elem.off('click').on('click', function(e) {
e.stopPropagation();
if($('div.tableSelect').length >= 1){
return false;
}
var t = elem.offset().top + elem.outerHeight()+"px";
var l = elem.offset().left +"px";
var tableName = "tableSelect_table_" + new Date().getTime();
var tableBox = '<div class="tableSelect layui-anim layui-anim-upbit" style="left:'+l+';top:'+t+';border: 1px solid #d2d2d2;background-color: #fff;box-shadow: 0 2px 4px rgba(0,0,0,.12);padding:10px 10px 0 10px;position: absolute;z-index:66666666;margin: 5px 0;border-radius: 2px;min-width:530px;">';
tableBox += '<div class="tableSelectBar">';
tableBox += '<form class="layui-form" action="" style="display:inline-block;">';
tableBox += '<input style="display:inline-block;width:190px;height:30px;vertical-align:middle;margin-right:-1px;border: 1px solid #C9C9C9;" type="text" name="'+opt.searchKey+'" placeholder="'+opt.searchPlaceholder+'" autocomplete="off" class="layui-input"><button class="layui-btn layui-btn-sm layui-btn-primary tableSelect_btn_search" lay-submit lay-filter="tableSelect_btn_search"><i class="layui-icon layui-icon-search"></i></button>';
tableBox += '</form>';
tableBox += '<button style="float:right;" class="layui-btn layui-btn-sm tableSelect_btn_select">选择<span></span></button>';
tableBox += '</div>';
tableBox += '<table id="'+tableName+'" lay-filter="'+tableName+'"></table>';
tableBox += '</div>';
tableBox = $(tableBox);
$('body').append(tableBox);
//数据缓存
var checkedData = [];
//渲染TABLE
opt.table.elem = "#"+tableName;
opt.table.id = tableName;
opt.table.done = function(res, curr, count){
defaultChecked(res, curr, count);
setChecked(res, curr, count);
tableDone(res, curr, count);
};
var tableSelect_table = table.render(opt.table);
//分页选中保存数组
table.on('radio('+tableName+')', function(obj){
if(opt.checkedKey){
checkedData = table.checkStatus(tableName).data
}
updataButton(table.checkStatus(tableName).data.length)
})
table.on('checkbox('+tableName+')', function(obj){
if(opt.checkedKey){
if(obj.checked){
for (var i=0;i<table.checkStatus(tableName).data.length;i++){
checkedData.push(table.checkStatus(tableName).data[i])
}
}else{
if(obj.type=='all'){
for (var j=0;j<table.cache[tableName].length;j++) {
for (var i=0;i<checkedData.length;i++){
if(checkedData[i][opt.checkedKey] == table.cache[tableName][j][opt.checkedKey]){
checkedData.splice(i,1)
}
}
}
}else{
//因为LAYUI问题,操作到变化全选状态时获取到的obj为空,这里用函数获取未选中的项。
function nu (){
var noCheckedKey = '';
for (var i=0;i<table.cache[tableName].length;i++){
if(!table.cache[tableName][i].LAY_CHECKED){
noCheckedKey = table.cache[tableName][i][opt.checkedKey];
}
}
return noCheckedKey
}
var noCheckedKey = obj.data[opt.checkedKey] || nu();
for (var i=0;i<checkedData.length;i++){
if(checkedData[i][opt.checkedKey] == noCheckedKey){
checkedData.splice(i,1);
}
}
}
}
checkedData = uniqueObjArray(checkedData, opt.checkedKey);
updataButton(checkedData.length)
}else{
updataButton(table.checkStatus(tableName).data.length)
}
});
//渲染表格后选中
function setChecked (res, curr, count) {
for(var i=0;i<res.data.length;i++){
for (var j=0;j<checkedData.length;j++) {
if(res.data[i][opt.checkedKey] == checkedData[j][opt.checkedKey]){
res.data[i].LAY_CHECKED = true;
var index= res.data[i]['LAY_TABLE_INDEX'];
var checkbox = $('#'+tableName+'').next().find('tr[data-index=' + index + '] input[type="checkbox"]');
checkbox.prop('checked', true).next().addClass('layui-form-checked');
var radio = $('#'+tableName+'').next().find('tr[data-index=' + index + '] input[type="radio"]');
radio.prop('checked', true).next().addClass('layui-form-radioed').find("i").html('&#xe643;');
}
}
}
var checkStatus = table.checkStatus(tableName);
if(checkStatus.isAll){
$('#'+tableName+'').next().find('.layui-table-header th[data-field="0"] input[type="checkbox"]').prop('checked', true);
$('#'+tableName+'').next().find('.layui-table-header th[data-field="0"] input[type="checkbox"]').next().addClass('layui-form-checked');
}
updataButton(checkedData.length)
}
//写入默认选中值(puash checkedData)
function defaultChecked (res, curr, count){
if(opt.checkedKey && elem.attr('ts-selected')){
var selected = elem.attr('ts-selected').split(",");
for(var i=0;i<res.data.length;i++){
for(var j=0;j<selected.length;j++){
if(res.data[i][opt.checkedKey] == selected[j]){
//cc.push(i);
checkedData.push(res.data[i])
table.setRowChecked(tableName, {
index:i,type:opt.table.cols[0][0].type
});
}
}
}
checkedData = uniqueObjArray(checkedData, opt.checkedKey);
}
// return cc;
}
//更新选中数量
function updataButton (n) {
tableBox.find('.tableSelect_btn_select span').html(n==0?'':'('+n+')')
}
//数组去重
function uniqueObjArray(arr, type){
var newArr = [];
var tArr = [];
if(arr.length == 0){
return arr;
}else{
if(type){
for(var i=0;i<arr.length;i++){
if(!tArr[arr[i][type]]){
newArr.push(arr[i]);
tArr[arr[i][type]] = true;
}
}
return newArr;
}else{
for(var i=0;i<arr.length;i++){
if(!tArr[arr[i]]){
newArr.push(arr[i]);
tArr[arr[i]] = true;
}
}
return newArr;
}
}
}
//FIX位置
var overHeight = (elem.offset().top + elem.outerHeight() + tableBox.outerHeight() - $(window).scrollTop()) > $(window).height();
var overWidth = (elem.offset().left + tableBox.outerWidth()) > $(window).width();
overHeight && tableBox.css({'top':'auto','bottom':'0px'});
overWidth && tableBox.css({'left':'auto','right':'5px'})
//关键词搜索
form.on('submit(tableSelect_btn_search)', function(data){
tableSelect_table.reload({
where: data.field,
page: {
curr: 1
}
});
return false;
});
//双击行选中
table.on('rowDouble('+tableName+')', function(obj){
var checkStatus = {data:[obj.data]};
selectDone(checkStatus);
})
//按钮选中
tableBox.find('.tableSelect_btn_select').on('click', function() {
var checkStatus = table.checkStatus(tableName);
if(checkedData.length > 1){
checkStatus.data = checkedData;
}
selectDone(checkStatus);
})
//写值回调和关闭
function selectDone (checkStatus){
if(opt.checkedKey){
var selected = [];
for(var i=0;i<checkStatus.data.length;i++){
selected.push(checkStatus.data[i][opt.checkedKey])
}
elem.attr("ts-selected",selected.join(","));
}
opt.done(elem, checkStatus);
tableBox.remove();
delete table.cache[tableName];
checkedData = [];
}
//点击其他区域关闭
$(document).mouseup(function(e){
var userSet_con = $(''+opt.elem+',.tableSelect');
if(!userSet_con.is(e.target) && userSet_con.has(e.target).length === 0){
tableBox.remove();
delete table.cache[tableName];
checkedData = [];
}
});
})
}
/**
* 隐藏选择器
*/
tableSelect.prototype.hide = function (opt) {
$('.tableSelect').remove();
}
//自动完成渲染
var tableSelect = new tableSelect();
//FIX 滚动时错位
if(window.top == window.self){
$(window).scroll(function () {
tableSelect.hide();
});
}
exports(MOD_NAME, tableSelect);
})
+466
View File
@@ -0,0 +1,466 @@
layui.define(["laydate","laytpl","table","layer"],function(exports) {
"use strict";
var moduleName = 'tableEdit',_layui = layui,laytpl = _layui.laytpl
,$ = _layui.$,laydate = _layui.laydate,table = _layui.table,layer = _layui.layer
,selectTpl = [ //单选下拉框模板
'<div class="layui-tableEdit-div" style="{{d.style}}">'
,'<ul class="layui-tableEdit-ul">'
,'{{# if(d.data){ }}'
,'{{# d.data.forEach(function(item){ }}'
,'{{# var selectedClass = d.callbackFn(item) }}'
,'<li class="{{ selectedClass }}" data-name="{{ item.name }}" data-value="{{ item.value }}">'
,'<div class="layui-unselect layui-form-checkbox" lay-skin="primary"><span>{{ item.value }}</span></div>'
,'</li>'
,'{{# }); }}'
,'{{# } else { }}'
,'<li>无数据</li>'
,'{{# } }}'
,'</ul>'
, '</div>'
].join('')
,selectMoreTpl = [ //多选下拉框模板
'<div class="layui-tableEdit-div" style="{{d.style}}">'
,'<div class="layui-tableEdit-tpl">'
,'<ul>'
,'{{# if(d.data){ }}'
,'{{# d.data.forEach(function(item){ }}'
,'{{# var selectedClass = d.callbackFn(item) }}'
,'<li class="{{ selectedClass }}" data-name="{{ item.name }}" data-value="{{ item.value }}">'
,'<div class="layui-unselect layui-form-checkbox" lay-skin="primary"><span>{{ item.value }}</span><i class="layui-icon layui-icon-ok"></i></div>'
,'</li>'
,'{{# }); }}'
,'{{# } else { }}'
,'<li>无数据</li>'
,'{{# } }}'
,'</ul>'
,'</div>'
,'<div style="line-height: 36px;">'
,'<div style="float: left">'
,'<button type="button" event-type="close" class="layui-btn layui-btn-sm layui-btn-primary">关闭</button>'
,'</div>'
,'<div style="text-align: right">'
,'<button event-type="confirm" type="button" class="layui-btn layui-btn-sm layui-btn-primary">确定</button>'
,'</div>'
,'</div>'
,'</div>'
].join('');
//组件用到的css样式
var thisCss = [];
thisCss.push('.layui-tableEdit-div{position:absolute;background-color:#fff;font-size:14px;border:1px solid #d2d2d2;z-index:19910908445;max-height: 252px;}');
thisCss.push('.layui-tableEdit-tpl{max-height:216px;overflow-y:auto;}');
thisCss.push('.layui-tableEdit-div li{line-height:36px;padding-left:5px;}');
thisCss.push('.layui-tableEdit-div li:hover{background-color:#f2f2f2;}');
thisCss.push('.layui-tableEdit-selected{background-color:#5FB878;}');
thisCss.push('.layui-tableEdit-checked i{background-color:#60b979!important;}');
thisCss.push('.layui-tableEdit-ul div{padding-left:0px!important;}');
thisCss.push('.layui-tableEdit-input{text-align:center;position:absolute;left:0;bottom:0;width:100%;height:38px;z-index: 19910908;}');
thisCss.push('.layui-tableEdit-add{position: absolute;right: 3px;top: 21px;margin-top: -15px;z-index: 199109084;}')
thisCss.push('.layui-tableEdit-sub{position: absolute;left: 3px;top: 21px;margin-top: -15px;z-index: 199109084;}')
var thisStyle = document.createElement('style');
thisStyle.innerHTML = thisCss.join('\n'),document.getElementsByTagName('head')[0].appendChild(thisStyle);
var configs = {
callbacks:{}
,
verify: {
required: [
/[\S]+/
,'必填项不能为空'
]
,phone: [
/^1[34578]\d{9}$/
,'请输入正确的手机号'
]
,email: [
/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
,'邮箱格式不正确'
]
,url: [
/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/
,'链接格式不正确'
]
,number:[
/(^[-+]?\d+$)|(^[-+]?\d+\.\d+$)/
,'只能填写数字'
]
,date: [
/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/
,'日期格式不正确'
]
,identity: [
/(^\d{15}$)|(^\d{17}(x|X|\d)$)/
,'请输入正确的身份证号'
]
}
};
var Class = function () { //单列模式 也就是只能new一个对象。
var instance;
Class = function Class() {
return instance;
};
Class.prototype = this; //保留原型属性
instance = new Class();
instance.constructor = Class; //重置构造函数指针
return instance
}; //构造器
var singleInstance = new Class();
var inFunc = function () {singleInstance.leaveStat = false;},outFunc = function () {singleInstance.leaveStat = true;};
document.onclick = function () {if(singleInstance.leaveStat)singleInstance.deleteAll();};
//日期选择框
Class.prototype.date = function(options){
var othis = this;
othis.callback = options.callback,othis.element = options.element,othis.dateType = options.dateType;
othis.dateType = othis.isEmpty(othis.dateType) ? "datetime":othis.dateType;
var that = options.element;
if ($(that).find('input').length>0)return;
othis.deleteAll(),othis.leaveStat = false;
var input = $('<input class="layui-input layui-tableEdit-input" type="text">');
(39 - that.offsetHeight > 3) && input.css('height','30px');
(that.offsetHeight - 39 > 3) && input.css('height','50px');
$(that).append(input),input.focus();
//日期时间选择器 (show: true 表示直接显示)
laydate.render({elem: input[0],type: othis.dateType,show: true,done:function (value, date) {
othis.deleteAll();
if(othis.callback)othis.callback.call(that,value);
}});
$('div.layui-laydate').hover(inFunc,outFunc),$(that).hover(inFunc,outFunc);
_layui.stope();
};
//输入框
Class.prototype.input = function(options){
var othis = this;
othis.callback = options.callback,othis.element = options.element;
othis.oldValue = options.oldValue;
othis.oldValue = othis.oldValue ? othis.oldValue : '';
var that = options.element;
if ($(that).find('input').length>0)return;
othis.deleteAll(),othis.leaveStat = false;
var input = $('<input class="layui-input layui-tableEdit-input" style="z-index: 99999999999" type="text">');
(39 - that.offsetHeight > 3) && input.css('height','30px');
(that.offsetHeight - 39 > 3) && input.css('height','50px');
input.val(othis.oldValue);
$(that).append(input),input.focus();
input.click(function (e) {
_layui.stope(e);
});
input.bind('change', function(e){othis.callback.call(othis.element,this.value)});
$(that).hover(inFunc,outFunc);
_layui.stope();
};
//带加号和减号的输入框(只支持输入数字)
Class.prototype.signedInput = function(options){
var othis = this;
othis.callback = options.callback,othis.element = options.element;
othis.oldValue = options.oldValue;
othis.oldValue = othis.oldValue ? othis.oldValue : '';
var that = options.element;
if ($(that).find('input').length>0)return;
othis.deleteAll(),othis.leaveStat = false;
var thisWidth = that.offsetWidth-49;
var input = $('<input class="layui-input layui-tableEdit-input" style="left: 24px;width: '+thisWidth+'px" type="text">');//
var leftBtn = $('<button type="button" class="layui-btn layui-btn-sm layui-tableEdit-sub"><i class="layui-icon layui-icon-subtraction" style="margin-top:-14px!important;position: absolute;left:2px!important"></i></button>');
var rightBtn = $('<button type="button" class="layui-btn layui-btn-sm layui-tableEdit-add"><i class="layui-icon layui-icon-addition" style="margin-top:-14px!important;position: absolute;right:-1px!important"></i></button>');
if(39 - that.offsetHeight > 3){
input.css('height','30px');leftBtn.css('top','16px');rightBtn.css('top','16px');
}
if(that.offsetHeight - 39 > 3){
input.css('height','50px');leftBtn.css('top','25px');rightBtn.css('top','25px');
}
input.val(othis.oldValue);
$(that).append(leftBtn);leftBtn.find('i').html('');
$(that).append(input),input.focus();$(that).append(rightBtn);rightBtn.find('i').html('');
input.click(function (e) {
_layui.stope(e);
});
input.bind('change', function(e){othis.callback.call(othis.element,this.value)});
$(that).hover(inFunc,outFunc);
_layui.stope();
$(that).find('button.layui-tableEdit-sub,button.layui-tableEdit-add').bind('click',function () {
var input = $(that).find('input.layui-tableEdit-input');
var val = input.val();
if(!val || val.length<=0)val=0;
val = parseInt(val);
if($(this).hasClass('layui-tableEdit-add')){
++val;input.val(val);
othis.callback.call(othis.element,val)
}else{
--val;input.val(val);
othis.callback.call(othis.element,val)
}
})
};
//判断是否为空函数
Class.prototype.isEmpty = function(dataStr){return typeof dataStr === 'undefined' || dataStr === null || dataStr.length <= 0;};
//生成下拉框函数入口
Class.prototype.register = function(options){
var othis = this;
othis.enabled = options.enabled,othis.callback = options.callback;
othis.data = options.data,othis.element = options.element;
othis.selectedData = options.selectedData;
var that = othis.element;
if($(that).find('input.layui-tableEdit-input')[0]) return;
othis.deleteAll(),othis.leaveStat = false;
var input = $('<input class="layui-input layui-tableEdit-input" placeholder="请选择">')
,tableEdit = $('<div class="layui-tableEdit"></div>')
,tableBody = $(that).parents('div.layui-table-body')
,tablePage = $(that).parents('div.layui-table-box').eq(0).next();
(39 - that.offsetHeight > 3) && input.css('height','30px');
(that.offsetHeight - 39 > 3) && input.css('height','50px');
tableEdit.append(input),$(that).append(tableEdit),input.focus();
var thisY = input[0].getBoundingClientRect().top //输入框y坐标
,thisHeight = ((39 - that.offsetHeight > 3) ? 30 : input[0].offsetHeight) //输入框高度
,thisHeight = ((that.offsetHeight - 39 > 3) ? 50 :thisHeight)
,thisWidth = input[0].offsetWidth //输入框宽度
,elemY = that.getBoundingClientRect().top //输入框y坐标
,tableBodyY = tableBody[0].getBoundingClientRect().top
,pageY = tablePage[0].getBoundingClientRect().top
,tableBodyHeight = tableBody.height() //表格高度
,isType = thisY-tableBodyY > 0.8*tableBodyHeight
,type = isType ? 'top: auto;bottom: '+(thisHeight+2)+'px;' : 'bottom: auto;top: '+(thisHeight+2)+'px;';
if(elemY<tableBodyY)tableBody[0].scrollTop = that.offsetTop; //调整滚动条位置
var style = type+'width: '+thisWidth+'px;left: 0px;'+(othis.enabled ? '':'overflow-y: auto;');
var getClassFn = function(item){
if(othis.isEmpty(othis.selectedData) || othis.isEmpty(item.name))return "";
var selectedClass;
if(typeof othis.selectedData === 'string' || Object.prototype.toString.call(othis.selectedData) === '[object Number]'){
selectedClass = (item.name+"" === othis.selectedData+"") || (item.value+"" === othis.selectedData+"") ? "layui-tableEdit-selected"+(othis.enabled ? " layui-tableEdit-checked":'') : "";
}
if(typeof othis.selectedData === 'object'){
selectedClass = (item.name+"" === othis.selectedData.name+"") ? "layui-tableEdit-selected"+(othis.enabled ? " layui-tableEdit-checked":'') : "";
}
if(Array.isArray(othis.selectedData)){
for(var i=0;i<othis.selectedData.length;i++){
selectedClass = (item.name+"" === othis.selectedData[i].name+"") ? "layui-tableEdit-selected layui-tableEdit-checked" : "";
if(!othis.isEmpty(selectedClass)) break;
}
}
return selectedClass;
};
tableEdit.append(laytpl(othis.enabled ? selectMoreTpl : selectTpl).render({data: othis.data,style: style,callbackFn:getClassFn}));
var $tableEdit = $('div.layui-tableEdit-div')[0];
(thisY+$tableEdit.offsetHeight+thisHeight > pageY) && !isType && (tableBody[0].scrollTop = that.offsetTop);//调整滚动条位置
othis.events();
};
//删除所有下拉框和时间选择框
Class.prototype.deleteAll = function(){
$('div.layui-tableEdit-div,div.layui-tableEdit,div.layui-laydate,input.layui-tableEdit-input,button.layui-tableEdit-sub,button.layui-tableEdit-add').remove();
delete this.leaveStat;//清除(离开状态属性)
};
//注册事件
Class.prototype.events = function(){
var othis = this;
var searchFunc = function(val){ //关键字搜索
$('div.layui-tableEdit-div li').each(function () {
othis.isEmpty(val) || $(this).data('value').indexOf(val) > -1 ? $(this).show() : $(this).hide();
});
},liClickFunc = function(){ //给li元素注册点击事件
var liArr = $('div.layui-tableEdit-div li');
liArr.unbind('click'),liArr.bind('click',function (e) {
_layui.stope(e);
if(othis.enabled){//多选
$(this).hasClass("layui-tableEdit-checked") ? ($(this).removeClass("layui-tableEdit-checked"),
$(this).removeClass("layui-tableEdit-selected"))
: $(this).addClass("layui-tableEdit-checked")
}else {//单选
othis.deleteAll();
if(othis.callback)othis.callback.call(othis.element,{name:$(this).data("name"),value:$(this).data("value")});
}
});
},btnClickFunc = function (){ //给button按钮注册点击事件
$("div.layui-tableEdit-div button").bind('click',function () {
var eventType = $(this).attr("event-type"), btn = this,dataList = new Array();
if(eventType === 'close') singleInstance.deleteAll(); //“关闭”按钮
if(eventType === 'confirm') { //“确定”按钮
$('div.layui-tableEdit-div li').each(function (e) {
if(!$(this).hasClass("layui-tableEdit-checked"))return;
dataList.push({name:$(this).data("name"),value:$(this).data("value")});
});
othis.deleteAll();
if(othis.callback)othis.callback.call(othis.element,dataList);
}
});
};
//事件注册
$(othis.element).find('input.layui-tableEdit-input').bind('input propertychange', function(){searchFunc(this.value)});
othis.enabled ? (liClickFunc(),btnClickFunc()) : liClickFunc();
$(othis.element).hover(inFunc,outFunc);
};
var AopEvent = function(cols){this.config = {colsConfig:{}};this.parseCols(cols)};//aop构造器
/**
* 解析出tableEdit组件所需要的配置信息
* @param cols
*/
AopEvent.prototype.parseCols = function(cols){
var that = this;
cols.forEach(function (ite) {
ite.forEach(function (item) {
if(!item.config)return;
that.config.colsConfig[item.field] = item.config;
});
});
};
/**
* aop代理event
* @param event 事件名称
* @param callback 回调函数
*/
AopEvent.prototype.on = function(event,callback){
var othis = this;othis.config.event = event,othis.config.callback = callback;
table.on(othis.config.event,function (obj) {
var zthis = this,field = $(zthis).data('field'),config = othis.config.colsConfig[field];
if(!config){
othis.config.callback.call(zthis,obj);return;
}
obj.field = field;
var callbackFn = function (res) {
if(config.verify && !othis.verify(res,config.verify,this))return; //验证为空
obj.value = Array.isArray(res) ? (res.length>0 ? res : [{name:'',value:''}]) : res;
othis.config.callback.call(zthis,obj);
if(!singleInstance.isEmpty(config.cascadeSelectField)){
var csElement = $(this.parentNode).find("td[data-field='"+config.cascadeSelectField+"']");
$(csElement).attr("cascadeSelect-data",JSON.stringify({data:res,field:field}));
}
};
var csd = $(this).attr("cascadeSelect-data");//联动数据
if(singleInstance.isEmpty(csd)){ //非联动事件
if(config.type === 'select'){
singleInstance.register({data:config.data,element:zthis,enabled:config.enabled,selectedData:obj.data[field],callback:callbackFn});
}else if(config.type === 'date'){
singleInstance.date({dateType:config.dateType,element:zthis,callback:callbackFn});
}else if(config.type === 'input'){
singleInstance.input({element:zthis,oldValue:obj.data[field],callback:callbackFn});
}else if(config.type === 'signedInput'){
singleInstance.signedInput({element:zthis,oldValue:obj.data[field],callback:callbackFn});
}else othis.config.callback.call(zthis,obj);
} else {//联动事件
if(config.type === 'date') return;
//获取当前单元格的table表格的lay-filter属性值
var filter = $(zthis).parents('div.layui-table-view').eq(0).prev().attr('lay-filter')
,rs = active.callbackFn.call(zthis,'clickBefore('+filter+')',JSON.parse(csd));
//异步操作,由使用者调用。
//判断条件为rs为空时。
if(singleInstance.isEmpty(rs)){
active.on("async("+filter+")",function (result) {
singleInstance.register({data:result.data,element:zthis,enabled:result.enabled,selectedData:obj.data[field],callback:callbackFn});
})
}else {
singleInstance.register({data:rs.data,element:zthis,enabled:rs.enabled,selectedData:obj.data[field],callback:callbackFn});
}
}
});
};
/**
* 验证数据是否符合要求
* @param data 被验证数据
* @param verify 正则参数
* @param td 当前单元格
* @returns {boolean} true验证通过 false验证未通过
*/
AopEvent.prototype.verify = function (data,verify,td) {
var verifyObj = configs.verify[verify.type];
var verifyMsg = verify.msg;
verifyMsg = verifyMsg ? verifyMsg : (verifyObj ? verifyObj[1] : '必填项不能为空');
if(singleInstance.isEmpty(data)){
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
if(Array.isArray(data) && data.length <= 0){
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
if((typeof data === 'object' && singleInstance.isEmpty(data.name))
|| data.name === 'undefined'){
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
if(!verifyObj && !verify.regx){
return true;
}
if(verify.regx){ //自定义正则判断
if(typeof verify.regx === "function"){//为函数时
if(verify.regx(data))return true;
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
if(typeof verify.regx === "string"){ //为字符串正则时
var regx = new RegExp(verify.regx);
if(regx.test(data))return true;
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
if(verify.regx.test(data))return true; //为正则时
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
if(!verifyObj[0].test(data)){
layer.tips(verifyMsg, td,{tipsMore:true});
return false;
}
return true;
};
/**
* 提交数据的验证
* @param options {elem:'#test',data:[],verifyKey:'id'}
* elem: 表格id,带井号 data: 验证数据,数组类型。
* verifyKey: data中的元素的唯一值字段,且必须在表格中有此字段的单元格。
* @returns {*}
*/
AopEvent.prototype.submitValidate = function (options) {
var that = this,failedTds = [];
if(!options || singleInstance.isEmpty(options.verifyKey)
|| singleInstance.isEmpty(options.data)
|| singleInstance.isEmpty(options.elem))return failedTds;
var body = $(options.elem).next().find('div.layui-table-box div.layui-table-body tr');
options.data.forEach(function (item) {
for(var field in item){
var config = that.config.colsConfig[field];
if(!config || !config.verify)continue;
var verify = config.verify;
var tds = body.find('td[data-field="'+options.verifyKey+'"]');
var thisTd;
tds.each(function () {
var text = $(this).find('div.layui-table-cell').text();
if(text+'' === item[options.verifyKey]+''){
thisTd = $(this);
}
});
if(!thisTd)continue;
var td = thisTd.parent().children('td[data-field="'+field+'"]');
if(!that.verify(item[field],verify,td))failedTds.push(td[0]);
}
});
return failedTds;
};
var active = {
aopObj:function(cols){return new AopEvent(cols);},
on:function (event,callback) {
var filter = event.match(/\((.*)\)$/),eventName = (filter ? (event.replace(filter[0],'')+'_'+ filter[1]) : event);
configs.callbacks[moduleName+'_'+eventName]=callback;
},
callbackFn:function (event,params) {
var filter = event.match(/\((.*)\)$/),eventName = (filter ? (event.replace(filter[0],'')+'_'+ filter[1]) : event);
var key = moduleName+'_'+eventName,func = configs.callbacks[key];
if(!func) return;
return func.call(this,params);
}
};
active.on("tableEdit(getEntity)",function () {
return singleInstance;
});
exports(moduleName, active);
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
/*table 过滤*/
.layui-table-filter {height:100%;cursor: pointer;position: absolute;right:15px;padding:0 5px;}
.layui-table-filter i {font-size: 12px;color: #ccc;}
.layui-table-filter:hover i {color: #666;}
.layui-table-filter.tableFilter-has i {color: #1E9FFF;}
.layui-table-filter-view {min-width:200px;background:#FFFFFF;border: 1px solid #d2d2d2;box-shadow: 0 2px 4px rgba(0,0,0,.12);position:absolute;top:0px;left:0px;z-index:90000000;}
.layui-table-filter-box {padding:10px;}
.layui-table-filter-box .loading {width: 100%;height: 100%;text-align: center;line-height: 150px;}
.layui-table-filter-box .loading i {font-size: 18px;}
.layui-table-filter-box input.layui-input {margin-bottom:10px;}
.layui-table-filter-box ul {border: 1px solid #eee;height:150px;overflow: auto;margin-bottom:10px;padding:5px 10px 5px 10px;}
.layui-table-filter-box ul li {padding:3px 0;}
.layui-table-filter-box ul.radio {padding:0px;}
.layui-table-filter-box ul.radio li {padding:0px;}
.layui-table-filter-box ul li .layui-form-radio {display: block;color:#666;margin:0px;padding:0px;transition: .1s linear;}
.layui-table-filter-box ul li .layui-form-radio div {display: block;padding:0 10px;}
.layui-table-filter-box ul li .layui-form-radio i {display: none;}
.layui-table-filter-box ul li .layui-form-radio:hover {background:#f9f9f9;}
.layui-table-filter-box ul li .layui-form-radio.layui-form-radioed {background:#5FB878;color: #fff;}
.layui-table-filter-date {margin-bottom:10px;}
.layui-table-filter-date .layui-laydate {box-shadow:none;border:0;}
@@ -0,0 +1,532 @@
/**
TABLEFILTER
**/
layui.define(['table', 'jquery', 'form', 'laydate'], function (exports) {
var MOD_NAME = 'tableFilter',
$ = layui.jquery,
table = layui.table,
form = layui.form,
laydate = layui.laydate;
var tableFilter = {
"v" : '1.0.0'
};
//缓存
tableFilter.cache = {}
//渲染
tableFilter.render = function(opt){
//配置默认值
var elem = $(opt.elem || '#table'),
elemId = elem.attr("id") || "table_" + new Date().getTime(),
filters = opt.filters || [],
parent = opt.parent || 'body',
mode = opt.mode || "local";
opt.done = opt.done || function(){};
//写入默认缓存
tableFilter.cache[elemId]={};
//主运行
var main = function (){
//默认过滤
if(mode == "local"){
var trsIndex = tableFilter.getShowTrIndex(elem, elemId, filters);
if(trsIndex.length > 0){
var trs = elem.next().find('.layui-table-body tr');
trs.each(function(i, tr){
if($.inArray($(tr).data("index"), trsIndex) != -1){
$(tr).removeClass("layui-hide")
}else{
$(tr).addClass("layui-hide")
}
})
}else{
elem.next().find('.layui-table-body tr').removeClass("layui-hide")
}
//FIX全选监听
tableFilter.fixAll(elem);
//重载表格尺寸 (FIX刷新表格时的表格异常)
table.resize(elemId);
}
//遍历过滤项
layui.each(filters, function(i, filter){
var filterField = filter.field,
filterName = filter.name || filter.field,
filterType = filter.type || "input",
filterData = filter.data || [],
filterUrl = filter.url || "";
//插入图标
var th = elem.next().find('.layui-table-header th[data-field="'+filterField+'"]');
var icon = filterType == 'input' ? 'layui-icon-search' : 'layui-icon-down';
var filterIcon = $('<span class="layui-table-filter layui-inline"><i class="layui-icon '+icon+'"></i></span>');
th.find('.layui-table-cell').append(filterIcon)
//图标默认高亮
if(tableFilter.cache[elemId][filterName]){
filterIcon.addClass("tableFilter-has")
}else{
filterIcon.removeClass("tableFilter-has")
}
//图标点击事件
filterIcon.on("click", function(e) {
e.stopPropagation();
//得到过滤项的选项
//如果开启本地 并且没设置数据 就读本地数据
if( !filter.data && !filterUrl && filterType != "input"){
filterData = tableFilter.eachTds(elem, filterField);
}
//弹出层
var t = $(this).offset().top + $(parent).scrollTop() + $(this).outerHeight() + 5 +"px";
var l_fix = filterType == "date" ? 530 : 164;
var l = $(this).offset().left - ($('body').outerWidth(true) - $(parent).outerWidth(true)) - l_fix +"px";
var filterBox = $('<div class="layui-table-filter-view layui-anim layui-anim-fadein" style="top:'+t+';left:'+l+';"><div class="layui-table-filter-box"><form class="layui-form" lay-filter="table-filter-form"></form></div></div>');
if(filterType == "input"){
filterBox.find('form').append('<input type="search" name="'+filterName+'" lay-verify="required" lay-verType="tips" placeholder="关键词" class="layui-input">');
}
if(filterType == "checkbox"){
filterBox.find('form').append('<ul></ul>');
if(!filterUrl){
layui.each(filterData, function(i, item){
filterBox.find('ul').append('<li><input type="checkbox" name="'+filterName+'['+item.key+']" value="'+item.key+'" title="'+item.value+'" lay-skin="primary"></li>');
})
}
}
if(filterType == "radio"){
filterBox.find('form').append('<ul class="radio"></ul>');
if(!filterUrl){
filterBox.find('ul').append('<li><input type="radio" name="'+filterName+'" value="" title="All" checked></li>');
layui.each(filterData, function(i, item){
filterBox.find('ul').append('<li><input type="radio" name="'+filterName+'" value="'+item.key+'" title="'+item.value+'"></li>');
})
}
}
if(filterType == "date"){
filterBox.find('form').append('<div class="layui-table-filter-date"></div>');
filterBox.find('form').append('<input type="text" name="'+filterName+'" lay-verify="required" lay-verType="tips" placeholder="请选择日期" class="layui-input">');
}
filterBox.find('form').append('<button class="layui-btn layui-btn-normal layui-btn-sm" lay-submit lay-filter="tableFilter">确定</button>');
filterBox.find('form').append('<button type="button" class="layui-btn layui-btn-primary layui-btn-sm filter-del layui-btn-disabled" disabled>取消过滤</button>');
//设置清除是否可用
$(this).hasClass('tableFilter-has') && filterBox.find('.filter-del').removeClass("layui-btn-disabled").removeAttr("disabled","disabled");
//加入DOM
$(parent).append(filterBox);
//赋值FORM
form.val("table-filter-form", tableFilter.toLayuiFrom(elemId, filterName, filterType));
//渲染layui form
form.render(null, 'table-filter-form');
//渲染日期
if(filterType == "date"){
laydate.render({
elem: '.layui-table-filter-date',
range: true,
type: 'date',
value: $('.layui-table-filter-date').next().val(),
position: 'static',
showBottom: false,
change: function(value, date, endDate){
$('.layui-table-filter-date').next().val(value)
}
});
}
//渲染FORM 如果是searchInput 就默认选中
var searchInput = filterBox.find('form input[type="search"]');
searchInput.focus().select();
//处理异步filterData
if((filterType == 'checkbox' || filterType == 'radio') && filterUrl){
var filterBoxUl = filterBox.find('.layui-table-filter-box ul');
filterBoxUl.append('<div class="loading"><i class="layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i></div>');
$.getJSON(filterUrl + "?_t=" + new Date().getTime(), function(res, status, xhr){
filterBoxUl.empty();
filterType == "radio" && filterBoxUl.append('<li><input type="radio" name="'+filterName+'" value="" title="All" checked></li>');
layui.each(res.data, function(i, item){
filterType == "checkbox" && filterBoxUl.append('<li><input type="checkbox" name="'+filterName+'['+item.key+']" value="'+item.key+'" title="'+item.value+'" lay-skin="primary"></li>');
filterType == "radio" && filterBoxUl.append('<li><input type="radio" name="'+filterName+'" value="'+item.key+'" title="'+item.value+'"></li>');
})
form.render(null, 'table-filter-form');
form.val("table-filter-form", tableFilter.toLayuiFrom(elemId, filterName, filterType));
});
}
//点击确认开始过滤
form.on('submit(tableFilter)', function(data){
//重构复选框结果
if(filterType == "checkbox"){
var NEWfield = [];
for(var key in data.field){
NEWfield.push(data.field[key])
}
data.field[filterName] = NEWfield
}
//过滤项写入缓存
tableFilter.cache[elemId][filterName] = data.field[filterName];
//如果有过滤项 icon就高亮
if(tableFilter.cache[elemId][filterName].length > 0){
filterIcon.addClass("tableFilter-has")
}else{
filterIcon.removeClass("tableFilter-has")
}
if(mode == "local"){
//本地交叉过滤
var trsIndex = tableFilter.getShowTrIndex(elem, elemId, filters);
if(trsIndex.length > 0 || data.field[filterName].length > 0){
var trs = elem.next().find('.layui-table-body tr');
trs.each(function(i, tr){
if($.inArray($(tr).data("index"), trsIndex) != -1){
$(tr).removeClass("layui-hide")
}else{
$(tr).addClass("layui-hide")
}
})
}else{
elem.next().find('.layui-table-body tr').removeClass("layui-hide")
}
//更新合计行
tableFilter.updataTotal(elem);
//更新序列号
tableFilter.upNumbers(elem);
//取消表格选中
tableFilter.uncheck(elem);
//重载表格尺寸
table.resize(elemId)
}else if(mode == "api"){
//服务端交叉过滤
//将数组转字符串
var new_where = {};
for (var key in tableFilter.cache[elemId]) {
var filterKey = key,
filterValue = tableFilter.cache[elemId][key];
if($.isArray(filterValue)){
new_where[filterKey] = filterValue.join(",");
}else{
new_where[filterKey] = filterValue;
}
}
table.reload(elemId,{"where":new_where})
}
//写入回调函数
opt.done(tableFilter.cache[elemId]);
filterBox.remove();
return false;
})
//点击清除此项过滤
filterBox.find('.layui-table-filter-box .filter-del').on('click', function(e) {
delete tableFilter.cache[elemId][filterName];
filterIcon.removeClass("tableFilter-has");
if(mode == "local"){
var trsIndex = tableFilter.getShowTrIndex(elem, elemId, filters);
if(trsIndex.length > 0){
var trs = elem.next().find('.layui-table-body tr');
trs.each(function(i, tr){
if($.inArray($(tr).data("index"), trsIndex) != -1){
$(tr).removeClass("layui-hide")
}else{
$(tr).addClass("layui-hide")
}
})
}else{
elem.next().find('.layui-table-body tr').removeClass("layui-hide")
}
//更新合计行
tableFilter.updataTotal(elem)
//更新序列号
tableFilter.upNumbers(elem)
//取消表格选中
tableFilter.uncheck(elem)
//重载表格尺寸
table.resize(elemId)
}else if(mode == "api"){
//需要清除where里的对应的值
var where = {};
where[filterName] = ''
table.reload(elemId,{"where" : where})
}
opt.done(tableFilter.cache[elemId]);
filterBox.remove();
})
//点击其他区域关闭
$(document).mouseup(function(e){
var userSet_con = $('.layui-table-filter-view');
if(!userSet_con.is(e.target) && userSet_con.has(e.target).length === 0){
filterBox.remove();
}
});
})
})
};
main();
//函数返回
var returnObj = {
'config' : opt,
'reload' : function(opt){
main();
//更新序列号
tableFilter.upNumbers(elem);
}
}
return returnObj
}
//遍历行获取本地列集合 return tdsArray[]
tableFilter.eachTds = function(elem, filterField){
var tdsText = [],
tdsArray = [];
var tds = elem.next().find('.layui-table-body td[data-field="'+filterField+'"]');
tds.each(function(i, td){
tdsText.push($.trim(td.innerText))
})
tdsText = tableFilter.tool.uniqueObjArray(tdsText);
layui.each(tdsText, function(i, item){
tdsArray.push({'key':item, 'value':item})
})
return tdsArray;
}
//获取匹配的TR的data-index return trsIndex[]
tableFilter.getShowTrIndex = function(elem, elemId, filters){
var trsIndex = [];
var filterValues = tableFilter.cache[elemId];
for (var key in filterValues) {
var filterKey = key,
filterValue = filterValues[key];
//如果有name比对filterField
layui.each(filters, function(i, item){
if(filterKey == item.name){
filterKey = item.field
}
})
var tds = elem.next().find('.layui-table-body td[data-field="'+filterKey+'"]');
//获取这一次过滤的匹配
var this_trsIndex = [];
tds.each(function(i, td){
if($.isArray(filterValue)){
//过滤值=数组 inArray 复选框
if($.inArray($.trim(td.innerText), filterValue) >= 0 && filterValue && filterValue.length > 0){
this_trsIndex.push($(td).parent().data("index"))
}
}else if(filterValue.indexOf(" - ") >= 0){
//是否在时间段内
var d = $.trim(td.innerText);
var s = filterValue.split(" - ")[0];
var e = filterValue.split(" - ")[1];
if(tableFilter.tool.isDuringDate(d,s,e)){
this_trsIndex.push($(td).parent().data("index"))
}
}else{
//过滤值=字符串 indexOf 单选框 输入框
if($.trim(td.innerText).indexOf(filterValue) >= 0){
this_trsIndex.push($(td).parent().data("index"))
}
}
})
//取最终结果 合并数组后去相同值
//第一次 不合并
if(trsIndex.length <= 0){
trsIndex = this_trsIndex
}else{
if(this_trsIndex.length > 0){
//这一次有值 和前面N次取相同值
trsIndex = tableFilter.tool.getSameArray(trsIndex, this_trsIndex);
}else{
//这一次没值 前面N次有值,如果字符串过滤未有值 就显示空
trsIndex = $.isArray(filterValue) ? trsIndex : [];
}
}
}
return tableFilter.tool.uniqueObjArray(trsIndex);
}
//JSON 数据转layuiFOMR 可用的 处理checkbox
tableFilter.toLayuiFrom = function(elemId, filterName, filterType){
var form_val = JSON.stringify(tableFilter.cache[elemId]);
form_val = JSON.parse(form_val);
if(filterType == "checkbox"){
layui.each(form_val[filterName], function(i, value){
form_val[filterName + "["+value+"]"] = true;
})
delete form_val[filterName];
}
return form_val;
}
//更新合计行数据
tableFilter.updataTotal = function(elem){
var elemId = elem.attr("id");
table.eachCols(elemId, function(i, item){
if(item.totalRow){
var tdAllnum = 0;
var tds = elem.next().find('.layui-table-body td[data-field="'+item.field+'"]')
tds.each(function(i, td){
if(!$(td).parent().hasClass('layui-hide')){
//FIX JS计算精度
tdAllnum = (tdAllnum*10 + Number($.trim(td.innerText))*10)/10
}
})
var totalTds = elem.next().find('.layui-table-total td[data-field="'+item.field+'"]')
totalTds.each(function(i, td){
$(td).find(".layui-table-cell").html(tdAllnum || "0")
})
}
})
}
//更新序号列
tableFilter.upNumbers = function(elem){
//当前第几页
var cur = elem.next().find('.layui-laypage-curr').text();
cur = Number(cur || '1')
var limit = elem.next().find('.layui-laypage-limits select').val();
limit = Number(limit)
var trs = elem.next().find('.layui-table-main tr');
var n = cur==1 ? 0 : limit*(cur-1);
trs.each(function(i, tr){
if(!$(tr).hasClass('layui-hide')){
n += 1;
$(tr).find('.laytable-cell-numbers').html(n)
}
})
if(elem.next().find('.layui-table-fixed').length >= 1){
var trs_f = elem.next().find('.layui-table-fixed .layui-table-body tr');
var n_f = cur==1 ? 0 : limit*(cur-1);
trs_f.each(function(i, tr_f){
if(!$(tr_f).hasClass('layui-hide')){
n_f += 1;
$(tr_f).find('.laytable-cell-numbers').html(n_f)
}
})
}
}
//表格取消选中
tableFilter.uncheck = function(elem){
var elemId = elem.attr("id");
var tableName = elem.attr("lay-filter");
var trs = elem.next().find('.layui-table-fixed-l tr');
trs.each(function(i, tr){
var c = $(tr).find("[name='layTableCheckbox']");
if(c.prop("checked")){
$(tr).find('.layui-form-checked i').click()
}
})
}
//FIX 表格全选选中隐藏项
tableFilter.fixAll = function(elem){
var elemId = elem.attr("id");
var tableName = elem.attr("lay-filter");
var trs = elem.next().find('.layui-table-main tr');
table.on('checkbox('+tableName+')', function(obj){
if(obj.type=="all"){
var data = table.cache[elemId];
trs.each(function(i, tr){
if($(tr).hasClass('layui-hide')){
data[i].LAY_CHECKED = false;
}
})
}
})
}
//隐藏选择器
tableFilter.hide = function(){
$('.layui-table-filter-view').remove();
}
//工具
tableFilter.tool = {
//数组&对象数组去重
'uniqueObjArray' : function(arr, type){
var newArr = [];
var tArr = [];
if(arr.length == 0){
return arr;
}else{
if(type){
for(var i=0;i<arr.length;i++){
if(!tArr[arr[i][type]]){
newArr.push(arr[i]);
tArr[arr[i][type]] = true;
}
}
return newArr;
}else{
for(var i=0;i<arr.length;i++){
if(!tArr[arr[i]]){
newArr.push(arr[i]);
tArr[arr[i]] = true;
}
}
return newArr;
}
}
},
//合并数组取相同项
'getSameArray' : function(arry1, arry2){
var newArr = [];
for (var i = 0; i < arry1.length; i++) {
for (var j = 0; j < arry2.length; j++) {
if(arry2[j] === arry1[i]){
newArr.push(arry2[j]);
}
}
}
return newArr;
},
'isDuringDate' : function(dateStr, beginDateStr, endDateStr){
var curDate = new Date(dateStr),
beginDate = new Date(beginDateStr),
endDate = new Date(endDateStr);
if (curDate >= beginDate && curDate <= endDate) {
return true;
}
return false;
}
}
//输出接口
exports(MOD_NAME, tableFilter);
}).link(layui.cache.base+"tablefilter/tableFilter.css?v="+(new Date).getTime());
+308
View File
@@ -0,0 +1,308 @@
/**
* Layui 文本输入工具组件
*
* @author iTanken
* @since 20200310
*/
layui.define(['jquery'], function (exports) {
var $ = layui.$, baseClassName = 'layext-text-tool', extClassName = 'layext-textool-pane',
style, alignRight = true, alignClass, nodes = [], tools = {
"hide": null, "count": null, "copy": null, "reset": null, "clear": null,
hideIndex: -1, countIndex: -1, copyIndex: -1, resetIndex: -1, clearIndex: -1,
hideName: "hide", countName: "count", copyName: "copy", resetName: "reset", clearName: "clear",
hideClass: "layext-textool-minmax", countClass: "layext-textool-count", maxClass: "layext-textool-max",
copyClass: "layext-textool-copy", resetClass: "layext-textool-reset", clearClass: "layext-textool-clear",
copyTextId: baseClassName + '-copy-text', lengthClass: 'layext-textool-length',
lengthOverClass: baseClassName + '-length-over', laytips: 'layext-textool-laytips'
}, defaultOptions = {
// 根据元素 id 值单独渲染,为空默认根据 class='layext-text-tool' 批量渲染
eleId: null,
// 批量设置输入框最大长度,可结合 eleId 单独设置最大长度
maxlength: -1,
// 初始化回调,无参
initEnd: $.noop,
// 显示回调,参数为当前输入框和工具条面板的 jQuery 对象
showEnd: $.noop,
// 隐藏回调,参数为当前输入框和工具条面板的 jQuery 对象
hideEnd: $.noop,
// 初始化展开,默认展开,否则收起
initShow: true,
// 工具条是否位于输入框内部,默认位于外部
inner: false,
// 工具条对齐方向,默认右对齐,可选左对齐 'left'
align: 'right',
// 启用指定工具模块,默认依次为字数统计、复制内容、重置内容、清空内容,按数组顺序显示
tools: ['count', 'copy', 'reset', 'clear'],
// 工具按钮提示类型,默认为 'title' 属性,可选 'laytips',使用 layer 组件的吸附提示, 其他值不显示提示
tipType: 'title',
// 吸附提示背景颜色
tipColor: '#01AAED',
// 工具条字体颜色
color: '#666666',
// 工具条背景颜色
bgColor: '#FFFFFF',
// 工具条边框颜色
borderColor: '#E6E6E6',
// 工具条附加样式类名
className: '',
// z-index
zIndex: 19891014
}, Class = function (custom) {
var _this = this;
_this.tipsAttr = null;
_this.selector = null;
_this.init(_this, custom || {});
};
/** 初始化 */
Class.prototype.init = function (_this, custom) {
_this.options = $.extend({}, defaultOptions, custom);
_this.selector = $.trim(_this.options.eleId) === '' ? '.' + baseClassName : '#' + _this.options.eleId;
_this.initStyle(_this);
_this.initPrototype();
$(_this.selector).each(function (i, n) {
var $this = $(this), maxlength = _this.options.maxlength;
!isNaN(maxlength) && maxlength > -1 && $this.attr('maxlength', maxlength);
_this.addTextool(_this, $this);
});
_this.initTips(_this);
typeof _this.options.initEnd === 'function' && _this.options.initEnd();
};
/** 初始化扩展样式 */
Class.prototype.initStyle = function (_this) {
_this.options.zIndex = isNaN(_this.options.zIndex) ? 0 : _this.options.zIndex || 0;
style = ['<style type="text/css">',
'#', tools.copyTextId, ' { width: 0; height: 0; position: absolute; top: -190000px; }',
_this.selector, ' { position: relative; z-index: ', _this.options.zIndex + (_this.options.inner ? 0 : 1), '; }',
_this.selector, ' + .', extClassName, ' { position: relative; z-index: ', _this.options.zIndex, '; margin-top: -2px; display: block; outline: none; }',
_this.selector, ' + .', extClassName, ' * { color: ', (_this.options.color || '#666666'), '; }',
_this.selector, ' + .', extClassName, ' a > i { font-size: 12px!important; }',
_this.selector, ' + .', extClassName, ' a { padding: 0 3px; cursor: pointer; }',
_this.selector, ' + .', extClassName, ' a:active { background-color: #E2E2E2; opacity: 0.8; }',
_this.selector, ' + .', extClassName, ' .', tools.lengthClass, ' * { font-family: Consolas, sans-serif; }',
_this.selector, ' + .', extClassName, ' .', tools.lengthClass, ' { display: inline-block; border-width: 0 1px; }', /* border: 1px solid #F6F6F6; */
_this.selector, ' + .', extClassName, ' .', tools.lengthClass, ' * { font-family: Consolas, sans-serif; }',
_this.selector, ' + .', extClassName, ' .', tools.lengthOverClass, ' { color: #FF5722; }',
_this.selector, ' + .', extClassName, ' .', tools.countClass, ', ', _this.selector, ' + .', extClassName, ' .', tools.maxClass, ' { display: inline-block; min-width: 26px; height: 16px; line-height: 18px; }',
_this.selector, ' + .', extClassName, ' > .layui-badge { overflow: hidden; border-color: ', (_this.options.borderColor || '#E6E6E6'), '; background-color: ', (_this.options.bgColor || '#FFFFFF'), '; }',
_this.selector, ' + .', extClassName, '-r.', extClassName, '-inner > .layui-badge { border-right: 0 none; border-radius: 15px 0 17px; margin-right: 1px; }',
_this.selector, ' + .', extClassName, '-l.', extClassName, '-inner > .layui-badge { border-left: 0 none; border-radius: 0 15px 0; margin-left: 1px; }',
_this.selector, ' + .', extClassName, '-inner > .layui-badge { top: -18px; border-bottom: 0 none; opacity: 0.8; }',
_this.selector, ' + .', extClassName, '-inner > .layui-badge:hover { opacity: 1; }',
_this.selector, ' + .', extClassName, ' .', tools.maxClass, ' { opacity: 0.9; }',
_this.selector, ' + .', extClassName, '-r { text-align: right; }',
_this.selector, ' + .', extClassName, '-l { text-align: left; }',
_this.selector, ' + .', extClassName, '-inner { height: 0; }',
'</style>'].join('');
$('head link:last')[0] && $('head link:last').after(style) || $('head').append(style);
};
/** 初始化默认方法,处理 JS 兼容问题 */
Class.prototype.initPrototype = function () {
// 获取数组元素下标
!Array.prototype.indexOf && (Array.prototype.indexOf = function (array, value) {
array = array || [];
for (var i = array.length; i--;) {
if (array[i] == value) {
return i;
}
}
return -1;
});
};
/** 添加文本工具 */
Class.prototype.addTextool = function (_this, $target) {
var $extPane = $target.next('.' + extClassName);
// 若已存在,则移除元素,支持重复渲染
$extPane && $extPane.length && $extPane.remove();
// 添加元素
$target.after(_this.getToolsNode(_this, $target));
$extPane = $target.next('.' + extClassName);
_this.setEvent(_this, $target, $extPane);
$extPane.fadeIn(200, function() {
!_this.options.initShow && $extPane.find('.' + tools.hideClass).trigger('click');
});
};
/** 复制文本 */
Class.prototype.copyText = function (_this, $target) {
if (!$target) {
return false;
}
!$('#' + tools.copyTextId).length && $('body').append('<textarea id=' + tools.copyTextId + ' readonly="readonly"></textarea>');
var $copy = $('#' + tools.copyTextId), value = $target.val();
$copy.val(value === '' ? ' ' : value).select();
document.execCommand('copy');
_this.showTip(_this, $target, '已复制!');
};
/** 设置内容长度 */
Class.prototype.setValLength = function (_this, $target) {
var $length = $target.next('.' + extClassName).find('.' + tools.countClass);
$length.text($target.val().length);
if ($target.val().length > $target.attr('maxlength')) {
$length.addClass(tools.lengthOverClass);
} else if ($length.hasClass(tools.lengthOverClass)) {
$length.removeClass(tools.lengthOverClass);
}
}
/** 设置工具条事件 */
Class.prototype.setEvent = function (_this, $target, $extPane) {
_this.setValLength(_this, $target);
var initValue = $target.val();
// 文本工具条按钮点击事件
$extPane.on('click', 'a', function (e) {
var $this = $(this), $icon = $this.children('i.layui-icon');
if ($this.hasClass(tools.hideClass)) {
// 收起展开按钮事件
$this.nextAll().toggle('fast');
$this.prevAll().toggle('fast');
if ($icon.hasClass('layui-icon-more')) {
$icon.removeClass('layui-icon-more').addClass('layui-icon-more-vertical');
$this.attr(_this.tipsAttr, '展开');
typeof _this.options.hideEnd === 'function' && _this.options.hideEnd($target, $extPane);
} else {
$icon.removeClass('layui-icon-more-vertical').addClass('layui-icon-more');
$this.attr(_this.tipsAttr, '收起');
typeof _this.options.showEnd === 'function' && _this.options.showEnd($target, $extPane);
}
_this.tipsAttr === tools.laytips && _this.showTip(_this, $this, $this.attr(_this.tipsAttr));
}
if ($this.hasClass(tools.copyClass)) {
// 复制按钮事件
_this.copyText(_this, $target);
}
if ($this.hasClass(tools.resetClass)) {
// 重置按钮事件
$target.val(initValue);
_this.setValLength(_this, $target);
}
if ($this.hasClass(tools.clearClass)) {
// 清空按钮事件
$target.val('');
_this.setValLength(_this, $target);
}
layui.stope(e);
return false;
});
// 字数统计事件
$target.on('keyup input', function (e) {
_this.setValLength(_this, $target);
layui.stope(e);
return false;
});
};
/** 获取工具条节点 */
Class.prototype.getToolsNode = function (_this, $target) {
if (!$target) return false;
// 总是显示收起展开按钮
tools.hide = ['<a href="javascript:;"', _this.getTips(_this, '收起'), 'class="', tools.hideClass, '"><i class="layui-icon layui-icon-more"></i></a>'].join('');
// 至少显示一个工具模块
_this.options.tools = _this.options.tools || [tools.countName];
// 字数统计
tools.countIndex = _this.options.tools.indexOf(tools.countName);
if (tools.countIndex > -1) {
var maxlength = $target.attr('maxlength') || -1;
tools.count = ['<span class="', tools.lengthClass, '"><b class="', tools.countClass, '"', _this.getTips(_this, '当前字数'), '>0</b>',
(maxlength < 0 ? '' : ['/<span class="', tools.maxClass, '"', _this.getTips(_this, '最大字数'), '>', maxlength, '</span>'].join('')), '</span>'].join('');
}
// 复制内容
tools.copyIndex = _this.options.tools.indexOf(tools.copyName);
if (tools.copyIndex > -1) {
tools.copy = ['<a href="javascript:;" class="', tools.copyClass, '"', _this.getTips(_this, '复制'),
'><i class="layui-icon layui-icon-file"></i></a>'].join('');
}
// 重置内容
tools.resetIndex = _this.options.tools.indexOf(tools.resetName);
if (tools.resetIndex > -1) {
tools.reset = ['<a href="javascript:;" class="', tools.resetClass, '"', _this.getTips(_this, '重置'),
'><i class="layui-icon layui-icon-refresh-1"></i></a>'].join('');
}
// 清空内容
tools.clearIndex = _this.options.tools.indexOf(tools.clearName);
if (tools.clearIndex > -1) {
tools.clear = ['<a href="javascript:;" class="', tools.clearClass, '"', _this.getTips(_this, '清空'),
'><i class="layui-icon layui-icon-close"></i></a>'].join('');
}
if (_this.options.align === 'left') {
// 居左对齐
alignRight = false;
alignClass = extClassName + '-l';
} else {
// 居右对其
alignRight = true;
alignClass = extClassName + '-r';
}
// 处理工具条节点
nodes = ['<span class="layui-unselect ', extClassName, ' ', alignClass, ' ', (_this.options.inner ? extClassName + '-inner ' : ''),
$.trim(_this.options.className), ' layui-anim layui-anim-fadein"><span class="layui-badge layui-badge-rim">'];
!alignRight && nodes.push(tools.hide);
for (var i = 0; i < _this.options.tools.length; i++) {
nodes.push(tools[_this.options.tools[i]] || '');
}
alignRight && nodes.push(tools.hide);
nodes.push('</span></span>');
return nodes.join('');
};
/** 获取提示信息属性 */
Class.prototype.getTips = function (_this, msg) {
switch (_this.options.tipType) {
case 'title':
_this.tipsAttr = 'title';
break;
case 'laytips':
_this.tipsAttr = tools.laytips;
break;
default:
return '';
}
return [' ', _this.tipsAttr, '=', msg, ' '].join('');
};
/** 初始化吸附提示 */
Class.prototype.initTips = function (_this) {
$('[' + tools.laytips + ']').each(function (i, n) {
var $target = $(n);
if ($.trim($target.attr(_this.tipsAttr)) !== '') {
$target.hover(function () {
_this.showTip(_this, $target, $target.attr(_this.tipsAttr));
}, _this.hideTip);
}
});
};
/** 显示吸附提示 */
Class.prototype.showTip = function (_this, $target, msg) {
_this.hideTip();
layui.layer.tips(msg, $target, { tips: [1, _this.options.tipColor || '#01AAED'], time: 2e3, anim: 5, zIndex: (_this.options.zIndex || 0) + 2 });
};
/** 隐藏吸附提示 */
Class.prototype.hideTip = function () {
layui.layer.closeAll('tips');
};
exports('textool', {
/** 初始化入口方法 */
init: function (custom) {
return new Class(custom);
}
});
});
File diff suppressed because one or more lines are too long
@@ -0,0 +1,271 @@
layui.define('table', function (exports) {
var $ = layui.$
, table = layui.table
//字符常量
, MOD_NAME = 'transferTable', ELEM = '.layui-transferTable'
//外部接口
, transferTable = {
index: layui.transferTable ? (layui.transferTable.index + 10000) : 0
//设置全局项
, set: function (options) {
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
, get: function (id) {
if (this.config && this.config[id]) {
return this.config[id].data
} else {
return []
}
}
, reload: function (id, options) {
table.reload(id, options)
}
}
//操作当前实例
, transfer = function () {
var that = this
, options = that.config
, id = options.id || options.index;
return {
reload: function (options) {
that.reload.call(that, options);
}
, config: options
}
}
//构造器
, Class = function (options) {
var that = this;
that.index = ++transferTable.index;
that.left_table_id = "left_table_" + that.index;
that.rigth_table_id = "rigth_table_" + that.index;
//表格重载ID 如果配置里面没有 自动分配一个ID
that.reload_left = that.left_table_id;
that.reload_right = that.rigth_table_id;
if (options.id && options.id.length) {
that.reload_left = options.id[0]
that.reload_right = options.id[1] || options.id[0] + '_2'
} else {
//没有配置ID 默认给表格中添加ID 用于重载
options.id = [that.reload_left, that.reload_right]
}
//全局设置
if (options.id_name) {
idName = options.id_name;
if (options.where && options.where[idName]) {
var d = [];
var tableid = that.reload_right;
d[tableid] = {data: options.where[idName]}
transferTable.set(d)
}
}
that.config = $.extend({}, that.config, transferTable.config, options);
that.render();
};
Class.prototype.render = function () {
//ID里面放表格样式
this.tableHtml()
// 配置表格参数
this.loadTable()
// 移动数据
this.moveData()
// 监听双击事件 并移动数据
this.doubleData()
}
Class.prototype.tableHtml = function () {
var that = this,
options = that.config,
left_table = '<table class="layui-hide" id="' + that.left_table_id + '" lay-filter="' + that.left_table_id + '"></table>',
rigth_table = '<table class="layui-hide" id="' + that.rigth_table_id + '" lay-filter="' + that.rigth_table_id + '"></table>',
html = '<div style="width:100%;margin:0 auto;overflow: hidden">' +
'<div style="width:45%;float: left;">' + left_table + '</div>' +
'<div style="width:10%;float: left;">' +
'<div class="btns" style="text-align: center;">' +
'<button data-tid="' + that.left_table_id + '" class="' + that.left_table_id + ' layui-btn layui-btn-disabled btn left" style="margin-bottom: 15px;"><i class="layui-icon layui-icon-next"></i></button><br>' +
'<button data-tid="' + that.rigth_table_id + '" class="' + that.rigth_table_id + ' layui-btn layui-btn-disabled btn rigth"><i class="layui-icon layui-icon-prev"></i></button>' +
'</div>' +
'</div>' +
'<div style="width:45%;float: left;">' + rigth_table + '</div>' +
'<div>';
$(options.elem).append(html)
}
Class.prototype.loadTable = function () {
//传递的参数 table.render 表格
var that = this,
options = that.config,
lt = [that.left_table_id, that.rigth_table_id]
$.each(lt, function (k, id) {
var config = {elem: '#' + id}
$.each(options, function (key, val) {
if (val[k] || val[k] === false) {
var value = val[k]
} else {
var value = val[0]
}
if (typeof val == 'function') {
config[key] = options[key]
} else if (key !== 'elem' && key !== 'id_name' && key !== 'where') {
config[key] = value
}
})
if (options.where) {
config.where = options.where
}
table.render(config);
})
//计算表格高度 居中中间按钮
var th = $('#' + lt[0]).next('div').height() / 2;
var bh = $('.btns').height() / 2;
$('.btns').css('margin-top', th - bh)
//监听表格选中
table.on('checkbox(' + that.left_table_id + ')', function (obj) {
//左边表格点击触发
var checkStatus = table.checkStatus(that.reload_left)
, data = checkStatus.data;
if (data.length > 0) {
$('.' + that.left_table_id).removeClass('layui-btn-disabled')
} else {
$('.' + that.left_table_id).addClass('layui-btn-disabled')
}
});
table.on('checkbox(' + that.rigth_table_id + ')', function (obj) {
//右边表格点击触发
var checkStatus = table.checkStatus(that.reload_right)
, data = checkStatus.data;
if (data.length > 0) {
$('.' + that.rigth_table_id).removeClass('layui-btn-disabled')
} else {
$('.' + that.rigth_table_id).addClass('layui-btn-disabled')
}
});
}
Class.prototype.moveData = function () {
//绑定点击事件
var that = this,
idName = that.config.id_name;
$('.' + that.left_table_id).on('click', function () {
if (!$(this).hasClass('layui-btn-disabled')) {
var checkStatus = table.checkStatus(that.reload_left)
, data = checkStatus.data;
that.leftReload(that, data)
}
$(this).addClass('layui-btn-disabled')
})
$('.' + that.rigth_table_id).on('click', function () {
if (!$(this).hasClass('layui-btn-disabled')) {
var checkStatus = table.checkStatus(that.reload_right)
, data = checkStatus.data;
that.rigthReload(that, data)
}
$(this).addClass('layui-btn-disabled')
})
}
Class.prototype.doubleData = function () {
var that = this;
table.on('rowDouble(' + that.left_table_id + ')', function (obj) {
//左边移动到右边
var data = [];
data.push(obj.data)
that.leftReload(that, data)
});
table.on('rowDouble(' + that.rigth_table_id + ')', function (obj) {
//右边移动到左边
var data = [];
data.push(obj.data)
that.rigthReload(that, data)
});
}
//重载表格
Class.prototype.leftReload = function (that, data) {
if (data && data.length > 0) {
if (that.config.where && that.config.where[idName]) {
var id_data = that.config.where[idName] + "";
id_data = id_data.split(',')
} else {
var id_data = [];
}
$.each(data, function (k, v) {
id_data.push('' + v[idName])
})
//全局存储
id_data = $.unique(id_data);
var ids_str = id_data.join(',')
var d = [];
var tableid = that.reload_right;
d[tableid] = {data: ids_str}
transferTable.set(d)
//配置存储ID
if (!that.config.where) {
that.config.where = {}
}
this.config.where[idName] = ids_str
//重载表格
var reload_config = {
page: {curr: 1},
where: {}
}
if (that.config.done) {
delete reload_config.page;
}
reload_config.where[idName] = ids_str
table.reload(that.reload_left, reload_config)
table.reload(that.reload_right, reload_config)
}
}
Class.prototype.rigthReload = function (that, data) {
if (data && data.length) {
var sel_data = [];
$.each(data, function (k, v) {
sel_data.push('' + v[idName])
})
var id_data = that.config.where[idName] + "";
id_data = id_data.split(',');
var moveD = []; //移除后保留的ID集合
$.each(id_data, function (k, v) {
if ($.inArray(v, sel_data) == -1) moveD.push(v)
})
id_data = $.unique(moveD);
var ids_str = id_data.join(',')
var d = [];
var tableid = that.reload_right;
d[tableid] = {data: ids_str}
transferTable.set(d)
//配置存储ID
this.config.where[idName] = ids_str
//重载表格
var reload_config = {
page: {curr: 1},
where: {}
}
if (that.config.done) {
delete reload_config.page;
}
reload_config.where[idName] = ids_str
table.reload(that.reload_left, reload_config)
table.reload(that.reload_right, reload_config)
}
}
transferTable.render = function (options) {
var ins = new Class(options);
return transfer.call(ins);
};
exports('transferTable', transferTable);
});
@@ -0,0 +1,18 @@
.treeTable-empty {
width: 20px;
display: inline-block;
}
.treeTable-icon {
cursor: pointer;
}
.treeTable-icon .layui-icon-triangle-d:before {
content: "\e623";
}
.treeTable-icon.open .layui-icon-triangle-d:before {
content: "\e625";
background-color: transparent;
}
@@ -0,0 +1,206 @@
layui.define(['layer', 'table'], function (exports) {
var $ = layui.jquery;
var layer = layui.layer;
var table = layui.table;
var treetable = {
// 渲染树形表格
render: function (param) {
// 检查参数
if (!treetable.checkParam(param)) {
return;
}
// 获取数据
if (param.data) {
treetable.init(param, param.data);
} else {
$.getJSON(param.url, param.where, function (res) {
treetable.init(param, res.data);
});
}
},
// 渲染表格
init: function (param, data) {
var mData = [];
var doneCallback = param.done;
var tNodes = data;
// 补上id和pid字段
for (var i = 0; i < tNodes.length; i++) {
var tt = tNodes[i];
if (!tt.id) {
if (!param.treeIdName) {
layer.msg('参数treeIdName不能为空', {icon: 5});
return;
}
tt.id = tt[param.treeIdName];
}
if (!tt.pid) {
if (!param.treePidName) {
layer.msg('参数treePidName不能为空', {icon: 5});
return;
}
tt.pid = tt[param.treePidName];
}
}
// 对数据进行排序
var sort = function (s_pid, data) {
for (var i = 0; i < data.length; i++) {
if (data[i].pid == s_pid) {
var len = mData.length;
if (len > 0 && mData[len - 1].id == s_pid) {
mData[len - 1].isParent = true;
}
mData.push(data[i]);
sort(data[i].id, data);
}
}
};
sort(param.treeSpid, tNodes);
// 重写参数
param.url = undefined;
param.data = mData;
param.page = {
count: param.data.length,
limit: param.data.length
};
param.cols[0][param.treeColIndex].templet = function (d) {
var mId = d.id;
var mPid = d.pid;
var isDir = d.isParent;
var emptyNum = treetable.getEmptyNum(mPid, mData);
var iconHtml = '';
for (var i = 0; i < emptyNum; i++) {
iconHtml += '<span class="treeTable-empty"></span>';
}
if (isDir) {
iconHtml += '<i class="layui-icon layui-icon-triangle-d"></i> <i class="layui-icon layui-icon-layer"></i>';
} else {
iconHtml += '<i class="layui-icon layui-icon-file"></i>';
}
iconHtml += '&nbsp;&nbsp;';
var ttype = isDir ? 'dir' : 'file';
var vg = '<span class="treeTable-icon open" lay-tid="' + mId + '" lay-tpid="' + mPid + '" lay-ttype="' + ttype + '">';
return vg + iconHtml + d[param.cols[0][param.treeColIndex].field] + '</span>'
};
param.done = function (res, curr, count) {
$(param.elem).next().addClass('treeTable');
$('.treeTable .layui-table-page').css('display', 'none');
$(param.elem).next().attr('treeLinkage', param.treeLinkage);
// 绑定事件换成对body绑定
/*$('.treeTable .treeTable-icon').click(function () {
treetable.toggleRows($(this), param.treeLinkage);
});*/
if (param.treeDefaultClose) {
treetable.foldAll(param.elem);
}
if (doneCallback) {
doneCallback(res, curr, count);
}
};
// 渲染表格
table.render(param);
},
// 计算缩进的数量
getEmptyNum: function (pid, data) {
var num = 0;
if (!pid) {
return num;
}
var tPid;
for (var i = 0; i < data.length; i++) {
if (pid == data[i].id) {
num += 1;
tPid = data[i].pid;
break;
}
}
return num + treetable.getEmptyNum(tPid, data);
},
// 展开/折叠行
toggleRows: function ($dom, linkage) {
var type = $dom.attr('lay-ttype');
if ('file' == type) {
return;
}
var mId = $dom.attr('lay-tid');
var isOpen = $dom.hasClass('open');
if (isOpen) {
$dom.removeClass('open');
} else {
$dom.addClass('open');
}
$dom.closest('tbody').find('tr').each(function () {
var $ti = $(this).find('.treeTable-icon');
var pid = $ti.attr('lay-tpid');
var ttype = $ti.attr('lay-ttype');
var tOpen = $ti.hasClass('open');
if (mId == pid) {
if (isOpen) {
$(this).hide();
if ('dir' == ttype && tOpen == isOpen) {
$ti.trigger('click');
}
} else {
$(this).show();
if (linkage && 'dir' == ttype && tOpen == isOpen) {
$ti.trigger('click');
}
}
}
});
},
// 检查参数
checkParam: function (param) {
if (!param.treeSpid && param.treeSpid != 0) {
layer.msg('参数treeSpid不能为空', {icon: 5});
return false;
}
if (!param.treeColIndex && param.treeColIndex != 0) {
layer.msg('参数treeColIndex不能为空', {icon: 5});
return false;
}
return true;
},
// 展开所有
expandAll: function (dom) {
$(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () {
var $ti = $(this).find('.treeTable-icon');
var ttype = $ti.attr('lay-ttype');
var tOpen = $ti.hasClass('open');
if ('dir' == ttype && !tOpen) {
$ti.trigger('click');
}
});
},
// 折叠所有
foldAll: function (dom) {
$(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () {
var $ti = $(this).find('.treeTable-icon');
var ttype = $ti.attr('lay-ttype');
var tOpen = $ti.hasClass('open');
if ('dir' == ttype && tOpen) {
$ti.trigger('click');
}
});
}
};
layui.link(layui.cache.base + "treetable-lay/treetable.css?v="+(new Date).getTime());
// 给图标列绑定事件
$('body').on('click', '.treeTable .treeTable-icon', function () {
var treeLinkage = $(this).parents('.treeTable').attr('treeLinkage');
if ('true' == treeLinkage) {
treetable.toggleRows($(this), true);
} else {
treetable.toggleRows($(this), false);
}
});
exports('treetable', treetable);
});
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+400
View File
@@ -0,0 +1,400 @@
(function (root, factory) {
// 世系模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.LineagePages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.LineagePages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
var selectedPersonId = '';
function normalizeList(data) {
// 通用列表响应可能是数组,也可能包在 rows、records、list、data 中。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 世系人物信息进入 innerHTML 前统一转义,避免姓名和简介污染页面结构。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-lineage-page], [data-family-home-page]');
return getQueryParam(search, 'id') ||
getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
'';
}
function toNumber(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : undefined;
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function formatSex(value) {
var text = String(value === undefined || value === null ? '' : value);
if (text === '0' || text === '男') return '男';
if (text === '1' || text === '女') return '女';
return '未知';
}
function getPersonId(item) {
return pick(item, ['personId', 'lineagePersonId', 'id'], '');
}
function buildLineagePersonBody(values) {
// LineagePersonBody 来自 APP.openapi.json,空值统一转为 undefined,避免提交无意义空字符串。
var source = values || {};
return {
appUserId: toNumber(source.appUserId),
personNo: trimOrUndefined(source.personNo),
personName: String(source.personName || '').trim(),
aliasName: trimOrUndefined(source.aliasName),
sex: String(source.sex || '').trim() || '0',
generationNo: toNumber(source.generationNo),
generationName: trimOrUndefined(source.generationName),
avatarOssId: toNumber(source.avatarOssId),
birthDate: trimOrUndefined(source.birthDate),
deathDate: trimOrUndefined(source.deathDate),
introduction: trimOrUndefined(source.introduction)
};
}
function buildPersonRow(item) {
var personId = getPersonId(item);
var name = pick(item, ['personName', 'name', 'realName'], '未命名成员');
var generationNo = pick(item, ['generationNo', 'generation', 'generationIndex'], '-');
var generationName = pick(item, ['generationName', 'generationText'], '未设置');
var sex = formatSex(pick(item, ['sex', 'gender'], ''));
var bound = pick(item, ['boundAccount', 'bindAccount', 'hasAccount', 'appUserId'], '') ? '已绑定账号' : '未绑定账号';
return '<button class="module-row lineage-row" type="button" data-lineage-person="' + escapeHtml(personId) + '">' +
'<div><h3>' + escapeHtml(name) + '</h3><p>第 ' + escapeHtml(generationNo) + ' 世 · ' + escapeHtml(generationName) + '字辈 · ' + escapeHtml(sex) + ' · ' + escapeHtml(bound) + '</p></div>' +
'<span class="pill">查看资料</span>' +
'</button>';
}
function getChildren(item) {
var source = item || {};
return normalizeList(source.children || source.childList || source.descendants);
}
function buildTreeNode(item) {
var personId = getPersonId(item);
var name = pick(item, ['personName', 'name', 'realName'], '未命名成员');
var generationNo = pick(item, ['generationNo', 'generation', 'generationIndex'], '-');
var children = getChildren(item);
var html = '<li><button type="button" class="lineage-node" data-lineage-person="' + escapeHtml(personId) + '">' +
'<strong>' + escapeHtml(name) + '</strong><span>第 ' + escapeHtml(generationNo) + ' 世</span></button>';
if (children.length) {
html += '<ul>' + children.map(buildTreeNode).join('') + '</ul>';
}
return html + '</li>';
}
function buildHomeSummary(detail, rootCount) {
// 家谱主页摘要优先展示后端家谱信息,世系根节点数量来自树接口。
var source = detail || {};
var genealogyNo = pick(source, ['genealogyNo', 'genealogyCode', 'code'], '未设置编号');
var hallName = pick(source, ['hallName', 'ancestralHall', 'tanghao'], '未设置');
var memberCount = pick(source, ['memberCount', 'personCount', 'members'], '0');
return genealogyNo + ' · 堂号 ' + hallName + ' · 共 ' + memberCount + ' 人 · ' + rootCount + ' 个世系根节点';
}
function renderTree(items) {
var container = query('[data-lineage-tree], [data-lineage-home-tree]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无世系树数据</div>';
return;
}
container.innerHTML = '<ul class="lineage-tree">' + list.map(buildTreeNode).join('') + '</ul>';
}
function renderPersons(items) {
var container = query('[data-lineage-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无世系人物</div>';
return;
}
container.innerHTML = list.map(buildPersonRow).join('');
}
function renderHomeDetail(detail, rootCount) {
var title = query('[data-family-home-title]');
var summary = query('[data-family-home-summary]');
var source = detail || {};
if (title) title.textContent = pick(source, ['genealogyName', 'name'], title.textContent || '家谱主页');
if (summary) summary.textContent = buildHomeSummary(source, rootCount);
}
function renderDetail(item) {
var container = query('[data-lineage-detail]');
var source = item || {};
var name = pick(source, ['personName', 'name', 'realName'], '未命名成员');
var intro = pick(source, ['introduction', 'intro', 'remark'], '暂无简介');
if (!container) return;
container.innerHTML = '<div class="form-like">' +
'<p><span>姓名</span><b>' + escapeHtml(name) + '</b><em>' + escapeHtml(formatSex(pick(source, ['sex', 'gender'], ''))) + '</em></p>' +
'<p><span>字辈</span><b>' + escapeHtml(pick(source, ['generationName', 'generationText'], '未设置')) + '</b><em>第 ' + escapeHtml(pick(source, ['generationNo', 'generation'], '-')) + ' 世</em></p>' +
'<p><span>生卒</span><b>' + escapeHtml(pick(source, ['birthDate'], '未填写')) + '</b><em>' + escapeHtml(pick(source, ['deathDate'], '健在或未填')) + '</em></p>' +
'<p><span>简介</span><b>' + escapeHtml(intro) + '</b><em>世系资料</em></p>' +
'</div>';
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
async function loadLineage() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var keyword = query('[data-lineage-keyword]');
var homeSummary = query('[data-family-home-summary]');
var treeData;
var treeList;
var queryData = {
pageNum: 1,
pageSize: 50
};
if (!api) return;
if (!genealogyId) {
renderTree([]);
renderPersons([]);
showMessage('请从具体家谱进入世系图');
return;
}
if (keyword && keyword.value.trim()) queryData.keyword = keyword.value.trim();
try {
treeData = await api.lineageTree(genealogyId);
treeList = normalizeList(treeData);
renderTree(treeData);
if (homeSummary && api.genealogyDetail) {
renderHomeDetail(await api.genealogyDetail(genealogyId), treeList.length);
}
if (query('[data-lineage-list]')) {
renderPersons(await api.lineagePersonsPage(genealogyId, queryData));
}
} catch (error) {
showMessage(error.message || '世系数据加载失败');
}
}
async function loadPersonDetail(personId) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
if (!api || !genealogyId || !personId) return;
selectedPersonId = personId;
queryAll('[data-lineage-person]').forEach(function (item) {
item.classList.toggle('is-selected', item.getAttribute('data-lineage-person') === String(personId));
});
try {
renderDetail(await api.lineagePersonDetail(genealogyId, personId));
} catch (error) {
showMessage(error.message || '人物详情加载失败');
}
}
async function submitPerson(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var body = buildLineagePersonBody(getFormValues(form));
if (!api || !genealogyId) {
showMessage('请从具体家谱进入世系图');
return;
}
if (!body.personName) {
showMessage('请填写成员姓名');
return;
}
try {
await api.createLineagePerson(genealogyId, body);
form.reset();
showMessage('世系人物已新增');
loadLineage();
} catch (error) {
showMessage(error.message || '新增世系人物失败');
}
}
async function createRelation(relationType) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var relationNames = {
parents: '父母',
spouses: '配偶',
children: '子女',
siblings: '兄弟姐妹'
};
var personName;
if (!api || !genealogyId || !selectedPersonId) {
showMessage('请先在成员列表中选择一个成员');
return;
}
personName = root.prompt('请输入要添加的' + (relationNames[relationType] || '亲属') + '姓名', '');
if (!personName) return;
try {
await api.addLineageRelation(genealogyId, selectedPersonId, relationType, buildLineagePersonBody({
personName: personName
}));
showMessage('亲属关系已新增');
loadLineage();
} catch (error) {
showMessage(error.message || '新增亲属关系失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-lineage-form]');
if (!form) return;
event.preventDefault();
submitPerson(form);
});
documentRef.addEventListener('click', function (event) {
var personButton = event.target.closest('[data-lineage-person]');
var searchButton = event.target.closest('[data-lineage-search]');
var relationButton = event.target.closest('[data-lineage-relation]');
if (personButton) {
event.preventDefault();
loadPersonDetail(personButton.getAttribute('data-lineage-person'));
}
if (searchButton) {
event.preventDefault();
loadLineage();
}
if (relationButton) {
event.preventDefault();
createRelation(relationButton.getAttribute('data-lineage-relation'));
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadLineage();
}
return {
normalizeList: normalizeList,
buildLineagePersonBody: buildLineagePersonBody,
formatSex: formatSex,
buildPersonRow: buildPersonRow,
buildTreeNode: buildTreeNode,
buildHomeSummary: buildHomeSummary,
init: init
};
});
+191
View File
@@ -0,0 +1,191 @@
var hexcase = 0;
var b64pad = "";
var chrsz = 8;
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function calcMD5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function md5_vm_test()
{
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}
function core_md5(x, len)
{
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a = 1732584193;
var b = -271733879;
var c = -1732584194;
var d = 271733878;
for(var i = 0; i < x.length; i += 16)
{
var olda = a;
var oldb = b;
var oldc = c;
var oldd = d;
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
a = safe_add(a, olda);
b = safe_add(b, oldb);
c = safe_add(c, oldc);
d = safe_add(d, oldd);
}
return Array(a, b, c, d);
}
function md5_cmn(q, a, b, x, s, t)
{
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function core_hmac_md5(key, data)
{
var bkey = str2binl(key);
if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
var ipad = Array(16), opad = Array(16);
for(var i = 0; i < 16; i++)
{
ipad[i] = bkey[i] ^ 0x36363636;
opad[i] = bkey[i] ^ 0x5C5C5C5C;
}
var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
return core_md5(opad.concat(hash), 512 + 128);
}
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function bit_rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt));
}
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
return bin;
}
function binl2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
function binl2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var str = "";
for(var i = 0; i < binarray.length * 4; i += 3)
{
var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16)
| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
| ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
for(var j = 0; j < 4; j++)
{
if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
}
}
return str;
}
+365
View File
@@ -0,0 +1,365 @@
(function (root, factory) {
// 成员与家族管理模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.MemberAdminPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.MemberAdminPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 成员接口返回可能是数组,也可能包在 rows、records、list、data 中。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 成员姓名、关系名进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-member-admin-page], [data-admin-permission-page], [data-family-invite-page], [data-family-share-page]');
return getQueryParam(search, 'id') ||
getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
'';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : undefined;
}
function formatRole(roleType) {
var role = String(roleType || '').trim();
var roleMap = {
owner: '创建者',
creator: '创建者',
admin: '管理员',
manager: '管理员',
member: '普通成员'
};
return roleMap[role] || role || '普通成员';
}
function buildMemberUpdateBody(values) {
// GenealogyMemberUpdateBody 来自 APP.openapi.json。
var source = values || {};
return {
memberName: trimOrUndefined(source.memberName),
relationName: trimOrUndefined(source.relationName),
roleType: String(source.roleType || '').trim() || 'member',
lineagePersonId: toNumber(source.lineagePersonId)
};
}
function buildOverviewSummary(detail) {
var source = detail || {};
var name = pick(source, ['genealogyName', 'name'], '当前家谱');
var memberCount = pick(source, ['memberCount', 'members', 'personCount'], '0');
var articleCount = pick(source, ['articleCount', 'articles'], '0');
var albumCount = pick(source, ['albumCount', 'albums'], '0');
return name + ' · ' + memberCount + ' 位成员 · ' + articleCount + ' 篇谱文 · ' + albumCount + ' 个相册';
}
function getMemberId(item) {
return pick(item, ['memberId', 'id', 'genealogyMemberId'], '');
}
function buildMemberRow(item) {
var memberId = getMemberId(item);
var name = pick(item, ['memberName', 'nickName', 'name'], '未命名成员');
var relation = pick(item, ['relationName', 'relation'], '族亲');
var roleType = pick(item, ['roleType', 'role'], 'member');
var bindName = pick(item, ['lineagePersonName', 'personName'], '未绑定');
return '<div class="module-row member-admin-row" data-member-id="' + escapeHtml(memberId) + '">' +
'<div><h3>' + escapeHtml(name) + '</h3><p>' + escapeHtml(relation) + ' · ' + escapeHtml(formatRole(roleType)) + ' · 绑定:' + escapeHtml(bindName) + '</p></div>' +
'<div class="row-actions"><button class="pill" type="button" data-member-edit="' + escapeHtml(memberId) + '" data-member-name="' + escapeHtml(name) + '" data-member-relation="' + escapeHtml(relation) + '" data-member-role="' + escapeHtml(roleType) + '">权限</button><button class="pill is-danger" type="button" data-member-remove="' + escapeHtml(memberId) + '">移除</button></div>' +
'</div>';
}
function buildOption(item) {
var memberId = getMemberId(item);
var name = pick(item, ['memberName', 'label', 'name'], '未命名成员');
return '<option value="' + escapeHtml(memberId) + '">' + escapeHtml(name) + '</option>';
}
function buildInviteLink(currentUrl, genealogyId) {
var url = new URL(currentUrl || 'http://localhost/profile-invite.html');
url.pathname = url.pathname.replace(/[^/]*$/, 'join-genealogy.html');
url.search = '?id=' + encodeURIComponent(genealogyId || '');
url.hash = '';
return url.toString();
}
function renderOverview(detail) {
var summary = query('[data-member-overview]');
var title = query('[data-member-title]');
if (title) title.textContent = pick(detail, ['genealogyName', 'name'], title.textContent || '家族管理');
if (summary) summary.textContent = buildOverviewSummary(detail);
}
function renderMembers(items) {
var container = query('[data-member-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无家谱成员</div>';
return;
}
container.innerHTML = list.map(buildMemberRow).join('');
}
function renderMemberOptions(items) {
var select = query('[data-member-select]');
var list = normalizeList(items);
if (!select) return;
select.innerHTML = '<option value="">请选择成员</option>' + list.map(buildOption).join('');
}
function renderInvite(detail, genealogyId) {
var code = query('[data-invite-code]');
var link = query('[data-invite-link]');
var currentUrl = root.location && root.location.href;
var inviteCode = pick(detail, ['inviteCode', 'genealogyNo', 'genealogyCode'], genealogyId || '未获取');
if (code) code.textContent = inviteCode;
if (link) link.textContent = buildInviteLink(currentUrl, genealogyId);
}
async function loadMemberAdmin() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var detail;
if (!api) return;
if (!genealogyId) {
showMessage('请从具体家谱进入管理页面');
return;
}
try {
detail = await api.genealogyOverview(genealogyId);
renderOverview(detail);
renderInvite(detail, genealogyId);
if (query('[data-member-list]')) {
renderMembers(await api.genealogyMembers(genealogyId));
}
if (query('[data-member-select]')) {
renderMemberOptions(await api.genealogyMemberOptions(genealogyId));
}
} catch (error) {
showMessage(error.message || '家族管理数据加载失败');
}
}
async function updateMemberFromPrompt(button) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var memberId = button.getAttribute('data-member-edit');
var roleType = root.prompt('请输入角色类型:owner/admin/member', button.getAttribute('data-member-role') || 'member');
if (!api || !genealogyId || !memberId || !roleType) return;
try {
await api.updateGenealogyMember(genealogyId, memberId, buildMemberUpdateBody({
memberName: button.getAttribute('data-member-name'),
relationName: button.getAttribute('data-member-relation'),
roleType: roleType
}));
showMessage('成员权限已更新');
loadMemberAdmin();
} catch (error) {
showMessage(error.message || '更新成员失败');
}
}
async function removeMember(memberId) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
if (!api || !genealogyId || !memberId) return;
if (!root.confirm('确定移除该成员?')) return;
try {
await api.removeGenealogyMember(genealogyId, memberId);
showMessage('成员已移除');
loadMemberAdmin();
} catch (error) {
showMessage(error.message || '移除成员失败');
}
}
async function submitPermission(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var memberId = query('[data-member-select]', form).value;
var roleType = query('[name="roleType"]', form).value;
if (!api || !genealogyId || !memberId) {
showMessage('请选择要设置的成员');
return;
}
try {
await api.updateGenealogyMember(genealogyId, memberId, buildMemberUpdateBody({
roleType: roleType
}));
showMessage('管理员权限已保存');
} catch (error) {
showMessage(error.message || '保存权限失败');
}
}
async function transferOwner() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var select = query('[data-member-select]');
if (!api || !genealogyId || !select || !select.value) {
showMessage('请选择要转让的成员');
return;
}
if (!root.confirm('确定转让家谱所有者?')) return;
try {
await api.transferGenealogyOwner(genealogyId, {
targetMemberId: Number(select.value)
});
showMessage('家谱所有者已转让');
} catch (error) {
showMessage(error.message || '转让失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('click', function (event) {
var editButton = event.target.closest('[data-member-edit]');
var removeButton = event.target.closest('[data-member-remove]');
var transferButton = event.target.closest('[data-owner-transfer]');
if (editButton) {
event.preventDefault();
updateMemberFromPrompt(editButton);
}
if (removeButton) {
event.preventDefault();
removeMember(removeButton.getAttribute('data-member-remove'));
}
if (transferButton) {
event.preventDefault();
transferOwner();
}
});
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-permission-form]');
if (!form) return;
event.preventDefault();
submitPermission(form);
});
}
function init() {
if (!documentRef) return;
bindActions();
loadMemberAdmin();
}
return {
normalizeList: normalizeList,
buildMemberUpdateBody: buildMemberUpdateBody,
buildOverviewSummary: buildOverviewSummary,
buildMemberRow: buildMemberRow,
buildInviteLink: buildInviteLink,
init: init
};
});
+247
View File
@@ -0,0 +1,247 @@
(function (root, factory) {
// 备忘录模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.MemoPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.MemoPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 备忘录列表兼容数组、rows、records、list、data。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 备忘标题和内容进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getCurrentGenealogyId() {
var search = root.location && root.location.search;
var page = query('[data-memo-page], [data-memo-edit-page]');
return getQueryParam(search, 'genealogyId') ||
(page && page.getAttribute('data-genealogy-id')) ||
getQueryParam(search, 'id') ||
'';
}
function getCurrentMemoId() {
var search = root.location && root.location.search;
return getQueryParam(search, 'memoId') || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function toNumber(value, fallback) {
var text = String(value === undefined || value === null ? '' : value).trim();
var number = Number(text);
return text && Number.isFinite(number) ? number : fallback;
}
function formatCompleted(value) {
return String(value || '0') === '1' ? '已完成' : '未完成';
}
function buildMemoBody(values) {
// MemoBody 来自 APP.openapi.jsonmemoTitle 必填。
var source = values || {};
return {
memoTitle: String(source.memoTitle || '').trim(),
memoContent: trimOrUndefined(source.memoContent),
remindTime: trimOrUndefined(source.remindTime),
completed: String(source.completed || '').trim() || '0',
mediaOssIds: trimOrUndefined(source.mediaOssIds),
sortOrder: toNumber(source.sortOrder, 1),
status: String(source.status || '').trim() || '0'
};
}
function getMemoId(item) {
return pick(item, ['memoId', 'id'], '');
}
function buildMemoRow(item, genealogyId) {
var memoId = getMemoId(item);
var title = pick(item, ['memoTitle', 'title'], '未命名备忘');
var completed = formatCompleted(pick(item, ['completed'], '0'));
var remindTime = pick(item, ['remindTime', 'createTime'], '未设置提醒');
return '<a class="module-row memo-row" href="profile-memo-edit.html?memoId=' + encodeURIComponent(memoId) + '&genealogyId=' + encodeURIComponent(genealogyId || '') + '">' +
'<div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(completed) + ' · ' + escapeHtml(remindTime) + '</p></div>' +
'<span class="pill">编辑</span></a>';
}
function renderMemos(items, genealogyId) {
var container = query('[data-memo-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无备忘录</div>';
return;
}
container.innerHTML = list.map(function (item) {
return buildMemoRow(item, genealogyId);
}).join('');
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
function fillMemoForm(memo) {
var source = memo || {};
queryAll('[name]').forEach(function (field) {
var value = pick(source, [field.name], '');
if (value !== '') field.value = value;
});
}
async function loadMemos() {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var memoId = getCurrentMemoId();
if (!api || !genealogyId) return;
try {
if (query('[data-memo-list]')) {
renderMemos(await api.memos(genealogyId), genealogyId);
}
if (memoId && query('[data-memo-edit-page]')) {
fillMemoForm(await api.memoDetail(genealogyId, memoId));
}
} catch (error) {
showMessage(error.message || '备忘录加载失败');
}
}
async function submitMemo(form) {
var api = getApi();
var genealogyId = getCurrentGenealogyId();
var memoId = getCurrentMemoId();
var body = buildMemoBody(getFormValues(form));
if (!api || !genealogyId) return;
if (!body.memoTitle) {
showMessage('请填写备忘标题');
return;
}
try {
if (memoId) {
await api.updateMemo(genealogyId, memoId, body);
} else {
await api.createMemo(genealogyId, body);
}
showMessage('备忘录已保存');
root.location.href = 'profile-memo.html?genealogyId=' + encodeURIComponent(genealogyId);
} catch (error) {
showMessage(error.message || '保存备忘录失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-memo-form]');
if (!form) return;
event.preventDefault();
submitMemo(form);
});
}
function init() {
if (!documentRef) return;
bindActions();
loadMemos();
}
return {
normalizeList: normalizeList,
buildMemoBody: buildMemoBody,
buildMemoRow: buildMemoRow,
init: init
};
});
+198
View File
@@ -0,0 +1,198 @@
(function (root, factory) {
// 消息模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.NotificationPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.NotificationPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 列表响应在不同接口中可能使用 rows、records、list 或 data 包裹。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 通知标题和正文来自接口,进入 innerHTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function isRead(item) {
var readStatus = pick(item, ['readStatus', 'status'], '');
var readFlag = pick(item, ['readFlag', 'isRead', 'read'], '');
if (readFlag === true || readFlag === 'true' || readFlag === 1 || readFlag === '1') return true;
return readStatus === '1' || readStatus === 1 || readStatus === '已读';
}
function formatNotificationStatus(item) {
return isRead(item) ? '已读' : '未读';
}
function buildNotificationRow(item) {
// 通知字段名按接口常见命名做兼容,页面只关心标题、内容、时间和已读状态。
var id = pick(item, ['notificationId', 'id'], '');
var title = pick(item, ['title', 'noticeTitle', 'messageTitle'], '系统通知');
var content = pick(item, ['content', 'message', 'noticeContent', 'summary'], '暂无通知内容');
var time = pick(item, ['createTime', 'createdAt', 'time'], '');
var status = formatNotificationStatus(item);
var className = isRead(item)
? 'module-row notification-row'
: 'module-row notification-row is-unread';
var action = isRead(item)
? '<span class="pill">已读</span>'
: '<button class="btn ghost" type="button" data-notification-read="' + escapeHtml(id) + '">标记已读</button>';
return '<div class="' + className + '" data-notification-id="' + escapeHtml(id) + '">' +
'<div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(time) + ' · ' + escapeHtml(content) + '</p></div>' +
action +
'</div>';
}
function renderNotifications(items) {
var container = query('[data-notification-list]');
if (!container) return;
if (!items.length) {
container.innerHTML = '<div class="api-empty">暂无消息通知</div>';
return;
}
container.innerHTML = items.map(buildNotificationRow).join('');
}
async function loadNotifications() {
var api = getApi();
var container = query('[data-notification-list]');
if (!api || !container) return;
container.classList.add('is-loading');
try {
renderNotifications(normalizeList(await api.notifications()));
} catch (error) {
showMessage(error.message || '消息通知加载失败');
} finally {
container.classList.remove('is-loading');
}
}
async function markRead(notificationId) {
var api = getApi();
if (!api || !notificationId) return;
try {
await api.markNotificationRead(notificationId);
showMessage('已标记为已读');
loadNotifications();
} catch (error) {
showMessage(error.message || '标记已读失败');
}
}
async function markAllRead() {
var api = getApi();
if (!api) return;
try {
await api.markAllNotificationsRead();
showMessage('已全部标记为已读');
loadNotifications();
} catch (error) {
showMessage(error.message || '全部标记已读失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('click', function (event) {
var readButton = event.target.closest('[data-notification-read]');
var readAllButton = event.target.closest('[data-notification-read-all]');
var refreshButton = event.target.closest('[data-notification-refresh]');
if (readButton) {
event.preventDefault();
markRead(readButton.getAttribute('data-notification-read'));
}
if (readAllButton) {
event.preventDefault();
markAllRead();
}
if (refreshButton) {
event.preventDefault();
loadNotifications();
}
});
}
function init() {
if (!documentRef) return;
bindActions();
loadNotifications();
}
return {
normalizeList: normalizeList,
formatNotificationStatus: formatNotificationStatus,
buildNotificationRow: buildNotificationRow,
renderNotifications: renderNotifications,
init: init
};
});
+39
View File
@@ -0,0 +1,39 @@
(function () {
// 只在精确指针设备上启用微动效,触屏和减少动效偏好下保持静态。
const finePointer = window.matchMedia("(hover: hover) and (pointer: fine)").matches;
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!finePointer || reduceMotion) return;
document.querySelectorAll(".tilt-card").forEach((card) => {
// 卡片倾斜角度通过 CSS 变量传递,具体视觉效果仍由 CSS 控制。
card.addEventListener("pointermove", (event) => {
const rect = card.getBoundingClientRect();
const px = (event.clientX - rect.left) / rect.width - 0.5;
const py = (event.clientY - rect.top) / rect.height - 0.5;
card.style.setProperty("--tilt-y", `${px * 5}deg`);
card.style.setProperty("--tilt-x", `${py * -5}deg`);
});
card.addEventListener("pointerleave", () => {
card.style.setProperty("--tilt-y", "0deg");
card.style.setProperty("--tilt-x", "0deg");
});
});
document.querySelectorAll(".magnetic").forEach((item) => {
// 品牌 logo 不做磁吸,避免导航视觉跳动。
if (item.classList.contains("brand") || item.querySelector(".brand-logo")) return;
item.addEventListener("pointermove", (event) => {
const rect = item.getBoundingClientRect();
const x = event.clientX - rect.left - rect.width / 2;
const y = event.clientY - rect.top - rect.height / 2;
item.style.transform = `translate(${x * 0.08}px, ${y * 0.08}px)`;
});
item.addEventListener("pointerleave", () => {
item.style.transform = "";
});
});
})();
+216
View File
@@ -0,0 +1,216 @@
(function (window, $) {
'use strict';
if (!$) return;
var layuiReady = false;
var layerApi = null;
function openLegacyLogout() {
var $modal = $('#logoutModal');
if (!$modal.length) return;
$modal.addClass('show').attr('aria-hidden', 'false');
$('body').addClass('logout-modal-open');
}
function closeLegacyLogout() {
var $modal = $('#logoutModal');
$modal.removeClass('show').attr('aria-hidden', 'true');
$('body').removeClass('logout-modal-open');
}
function openConfirm(options) {
var settings = $.extend({
title: '确认操作',
content: '确定继续吗?',
confirmText: '确定',
cancelText: '取消',
onConfirm: $.noop
}, options || {});
if (layerApi) {
layerApi.confirm(settings.content, {
title: settings.title,
btn: [settings.confirmText, settings.cancelText],
skin: 'profile-layer-confirm'
}, function (index) {
settings.onConfirm();
layerApi.close(index);
});
return;
}
if (window.confirm(settings.content)) settings.onConfirm();
}
function initLayui() {
if (!window.layui || layuiReady) return;
layuiReady = true;
window.layui.use(['layer', 'form'], function () {
layerApi = window.layui.layer;
if (window.layui.form) window.layui.form.render();
});
}
function bindLogout() {
$(document).on('click', '[data-logout-open]', function (event) {
var targetUrl = $(this).attr('data-logout-url') || 'login.html';
event.preventDefault();
if (!layerApi) {
openLegacyLogout();
return;
}
openConfirm({
title: '退出登录',
content: '确认退出当前账号吗?退出后需要重新登录才能继续管理家谱。',
confirmText: '确认退出',
onConfirm: function () {
window.location.href = targetUrl;
}
});
});
$(document).on('click', '[data-logout-close]', function () {
closeLegacyLogout();
});
$(document).on('keydown', function (event) {
if (event.key === 'Escape') closeLegacyLogout();
});
}
function bindConfirmActions() {
$(document).on('click', '[data-layer-confirm]', function (event) {
var $item = $(this);
var href = $item.attr('href');
event.preventDefault();
openConfirm({
title: $item.attr('data-confirm-title') || '确认操作',
content: $item.attr('data-layer-confirm') || '确定继续吗?',
confirmText: $item.attr('data-confirm-text') || '确定',
onConfirm: function () {
if (href && href !== '#') window.location.href = href;
}
});
});
}
function updateDisplay($trigger, value) {
var target = $trigger.attr('data-update-target');
var $target = target ? $(target) : $trigger.closest('p').find('b').first();
var $title;
if (!value) return;
if ($target.length) {
$target.text(value);
return;
}
$title = $trigger.closest('.module-row').find('h3').first();
if ($title.length) {
$title.text($title.text().replace(/([:]).*$/, '$1' + value));
}
}
function bindPromptActions() {
$(document).on('click', '[data-layer-prompt]', function (event) {
var $item = $(this);
var title = $item.attr('data-prompt-title') || $item.text() || '填写内容';
var placeholder = $item.attr('data-layer-prompt') || '';
var formType = $item.attr('data-prompt-type') === 'textarea' ? 2 : 0;
event.preventDefault();
if (!layerApi) {
var fallbackValue = window.prompt(placeholder || title, '');
if (fallbackValue) updateDisplay($item, fallbackValue);
return;
}
layerApi.prompt({
title: title,
value: $item.attr('data-prompt-value') || '',
formType: formType,
maxlength: Number($item.attr('data-prompt-maxlength')) || 200
}, function (value, index) {
updateDisplay($item, value);
layerApi.close(index);
layerApi.msg('已更新');
});
});
}
function bindSelectActions() {
$(document).on('click', '[data-layer-select]', function (event) {
var $item = $(this);
var values = ($item.attr('data-layer-select') || '').split('|').filter(Boolean);
var title = $item.attr('data-select-title') || '请选择';
var html = '<div class="profile-popup-select">';
event.preventDefault();
if (!values.length) return;
$.each(values, function (_, value) {
html += '<button type="button" data-popup-value="' + value + '">' + value + '</button>';
});
html += '</div>';
if (!layerApi) {
updateDisplay($item, values[0]);
return;
}
layerApi.open({
title: title,
content: html,
area: ['360px', 'auto'],
skin: 'profile-layer-confirm',
success: function (layero, index) {
layero.find('[data-popup-value]').on('click', function () {
updateDisplay($item, $(this).attr('data-popup-value'));
layerApi.close(index);
layerApi.msg('已选择');
});
}
});
});
}
function bindMessageActions() {
$(document).on('click', '[data-layer-msg]', function (event) {
event.preventDefault();
if (layerApi) layerApi.msg($(this).attr('data-layer-msg'));
});
}
function bindSelectableCards() {
$(document).on('click', '[data-select-card]', function () {
var $card = $(this);
var group = $card.attr('data-select-card');
if (group) $('[data-select-card="' + group + '"]').removeClass('is-selected');
$card.addClass('is-selected');
});
}
$(function () {
initLayui();
bindLogout();
bindConfirmActions();
bindPromptActions();
bindSelectActions();
bindMessageActions();
bindSelectableCards();
});
window.ProfileUI = {
confirm: openConfirm,
closeLogout: closeLegacyLogout,
initLayui: initLayui
};
})(window, window.jQuery || (window.layui && window.layui.$));
+223
View File
@@ -0,0 +1,223 @@
(function (root, factory) {
// 个人资料模块同时支持浏览器页面和 Node 测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.ProfilePages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.ProfilePages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function pick(item, keys, fallback) {
// 后端资料字段可能有 nickName、userName、phone 等不同名称,按优先级取值。
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function trimOrUndefined(value) {
var text = value === undefined || value === null ? '' : String(value).trim();
return text || undefined;
}
function toNumberOrUndefined(value) {
var text = trimOrUndefined(value);
var numberValue;
if (!text) return undefined;
numberValue = Number(text);
return Number.isNaN(numberValue) ? undefined : numberValue;
}
function getAvatarText(profile) {
// 头像字只取展示名第一个字符,避免接口没有头像时页面空白。
var displayName = pick(profile, ['nickName', 'userName', 'phone'], '家');
return String(displayName).charAt(0) || '家';
}
function buildRegionText(profile) {
var parts = [
profile && profile.provinceCode,
profile && profile.cityCode,
profile && profile.districtCode
].filter(Boolean);
return parts.length ? parts.join(' / ') : '待填写';
}
function buildProfileView(profile) {
// 页面展示模型和接口返回分开,后续改文案不影响接口契约。
return {
displayName: pick(profile, ['nickName', 'userName', 'phone'], '未设置昵称'),
avatarText: getAvatarText(profile),
phone: pick(profile, ['phone', 'phonenumber', 'mobile'], '未绑定'),
sex: pick(profile, ['sex'], '待填写'),
birthday: pick(profile, ['birthday'], '待填写'),
regionText: buildRegionText(profile || {})
};
}
function buildProfileUpdateBody(values) {
// 字段名称严格对应 PC YAML 里的 ProfileUpdateBody。
var source = values || {};
return {
nickName: trimOrUndefined(source.nickName),
avatarOssId: toNumberOrUndefined(source.avatarOssId),
sex: trimOrUndefined(source.sex),
birthday: trimOrUndefined(source.birthday),
provinceCode: trimOrUndefined(source.provinceCode),
cityCode: trimOrUndefined(source.cityCode),
districtCode: trimOrUndefined(source.districtCode)
};
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
if (!documentRef) return null;
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
if (!documentRef) return [];
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
if (root.alert) {
root.alert(message);
}
}
function setStatus(form, message) {
var statusNode = query('[data-profile-status]', form);
if (statusNode) {
statusNode.textContent = message || '';
}
}
function setSubmitting(form, isSubmitting) {
queryAll('button[type="submit"]', form).forEach(function (button) {
button.disabled = isSubmitting;
});
}
function renderProfile(view) {
// 所有资料展示点用 data-profile-text 标记,避免按中文文案查找节点。
queryAll('[data-profile-text]').forEach(function (node) {
var key = node.getAttribute('data-profile-text');
var value = view[key];
if (value !== undefined && value !== null && value !== '') {
node.textContent = value;
}
});
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
function fillProfileForm(profile) {
var form = query('[data-profile-form]');
var source = profile || {};
if (!form) return;
queryAll('[name]', form).forEach(function (field) {
if (source[field.name] !== undefined && source[field.name] !== null) {
field.value = source[field.name];
}
});
}
async function loadProfile() {
var api = getApi();
var profile;
if (!api || !documentRef || !documentRef.querySelector('[data-profile-page]')) return;
try {
profile = await api.currentProfile();
renderProfile(buildProfileView(profile));
fillProfileForm(profile);
} catch (error) {
showMessage(error.message || '个人资料加载失败');
}
}
async function submitProfileForm(form) {
var api = getApi();
if (!api || !form) return;
try {
setSubmitting(form, true);
setStatus(form, '保存中...');
await api.updateProfile(buildProfileUpdateBody(getFormValues(form)));
setStatus(form, '已保存');
showMessage('个人资料已保存');
await loadProfile();
} catch (error) {
setStatus(form, '保存失败');
showMessage(error.message || '个人资料保存失败');
} finally {
setSubmitting(form, false);
}
}
function bindProfileForm() {
var form = query('[data-profile-form]');
if (!form) return;
form.addEventListener('submit', function (event) {
event.preventDefault();
submitProfileForm(form);
});
}
function init() {
bindProfileForm();
loadProfile();
}
return {
pick: pick,
getAvatarText: getAvatarText,
buildProfileView: buildProfileView,
buildProfileUpdateBody: buildProfileUpdateBody,
init: init
};
});
+220
View File
@@ -0,0 +1,220 @@
(function (root, factory) {
// 推广内容模块同时服务应用介绍、下载页和公告详情页。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.PromotionPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.PromotionPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 推广接口使用通用列表响应,兼容后端常见数组包裹字段。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 标题、摘要、链接等普通文本进入 HTML 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getQueryParam(search, name) {
var params = new URLSearchParams(String(search || '').replace(/^\?/, ''));
return params.get(name) || '';
}
function getPromotionId(item) {
return String(pick(item, ['promotionId', 'id', 'articleId'], ''));
}
function getTitle(item) {
return pick(item, ['promotionTitle', 'title', 'name'], '推广内容');
}
function getSummary(item) {
return pick(item, ['summary', 'description', 'promotionDesc', 'remark'], '了解平台最新内容与应用服务。');
}
function getContent(item) {
return pick(item, ['promotionContent', 'content', 'articleContent'], '<p>暂无详细内容</p>');
}
function getTime(item) {
return pick(item, ['publishTime', 'createTime', 'updateTime'], '');
}
function getLink(item, fallback) {
return pick(item, ['linkUrl', 'url', 'targetUrl'], fallback || 'notice-detail.html?id=' + encodeURIComponent(getPromotionId(item)));
}
function getCover(item) {
return pick(item, ['coverUrl', 'coverImage', 'imageUrl', 'bannerUrl'], 'public/images/app-home.png');
}
function buildPromotionCard(item) {
var title = getTitle(item);
var summary = getSummary(item);
var time = getTime(item);
var link = getLink(item);
return '<a class="promotion-card" href="' + escapeHtml(link) + '" data-promotion-id="' + escapeHtml(getPromotionId(item)) + '">' +
'<img src="' + escapeHtml(getCover(item)) + '" alt="' + escapeHtml(title) + '" />' +
'<div><h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(summary) + '</p><span>' + escapeHtml(time) + '</span></div></a>';
}
function buildDownloadCard(item) {
var title = getTitle(item);
var summary = getSummary(item);
var link = getLink(item, 'download.html');
return '<a class="card soft download-card tilt-card" href="' + escapeHtml(link) + '" data-promotion-id="' + escapeHtml(getPromotionId(item)) + '">' +
'<h3>' + escapeHtml(title) + '</h3><p>' + escapeHtml(summary) + '</p></a>';
}
function pickPromotion(list, promotionId) {
var items = normalizeList(list);
var id = String(promotionId || '');
var index;
if (!items.length) return null;
if (!id) return items[0];
for (index = 0; index < items.length; index += 1) {
if (getPromotionId(items[index]) === id) return items[index];
}
return items[0];
}
function buildNoticeDetail(item) {
return {
title: getTitle(item),
summary: getSummary(item),
content: getContent(item),
time: getTime(item)
};
}
function renderPromotionCards(items) {
var container = query('[data-promotion-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无推广内容</div>';
return;
}
container.innerHTML = list.map(buildPromotionCard).join('');
}
function renderDownloadCards(items) {
var container = query('[data-promotion-download-list]');
var list = normalizeList(items);
if (!container) return;
if (!list.length) {
container.innerHTML = '<div class="api-empty">暂无下载推广内容</div>';
return;
}
container.innerHTML = list.map(buildDownloadCard).join('');
}
function renderNoticeDetail(items) {
var search = root.location && root.location.search;
var selected = pickPromotion(items, getQueryParam(search, 'id'));
var detail = selected ? buildNoticeDetail(selected) : null;
var title = query('[data-promotion-title]');
var summary = query('[data-promotion-summary]');
var content = query('[data-promotion-content]');
var time = query('[data-promotion-time]');
if (!detail) return;
if (title) title.textContent = detail.title;
if (summary) summary.textContent = detail.summary;
if (content) content.innerHTML = detail.content;
if (time) time.textContent = detail.time || '发布时间待定';
}
async function loadPromotions() {
var api = getApi();
var data;
if (!api) return;
try {
data = await api.promotions();
renderPromotionCards(data);
renderDownloadCards(data);
renderNoticeDetail(data);
} catch (error) {
showMessage(error.message || '推广内容加载失败');
}
}
function init() {
if (!documentRef || !query('[data-promotion-page]')) return;
loadPromotions();
}
return {
normalizeList: normalizeList,
buildPromotionCard: buildPromotionCard,
buildDownloadCard: buildDownloadCard,
pickPromotion: pickPromotion,
buildNoticeDetail: buildNoticeDetail,
init: init
};
});
+3
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+228
View File
@@ -0,0 +1,228 @@
(function (root, factory) {
// 行政区划模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.RegionPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.RegionPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function normalizeList(data) {
// 行政区划接口使用通用 ListResult,兼容常见数组包裹字段。
if (Array.isArray(data)) return data;
if (!data || typeof data !== 'object') return [];
if (Array.isArray(data.rows)) return data.rows;
if (Array.isArray(data.records)) return data.records;
if (Array.isArray(data.list)) return data.list;
if (Array.isArray(data.data)) return data.data;
return [];
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function escapeHtml(value) {
// 地区名称和编码进入 option 前统一转义。
return String(value === undefined || value === null ? '' : value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function getRegionCode(item) {
return pick(item, ['regionCode', 'code', 'value'], '');
}
function getRegionName(item) {
return pick(item, ['regionName', 'name', 'label'], '未命名地区');
}
function buildRegionOption(item) {
return '<option value="' + escapeHtml(getRegionCode(item)) + '">' + escapeHtml(getRegionName(item)) + '</option>';
}
function buildPathText(items) {
return normalizeList(items).map(function (item) {
return getRegionName(item);
}).filter(Boolean).join(' / ');
}
function getFinalRegionCode(values) {
var source = values || {};
return source.districtCode || source.cityCode || source.provinceCode || '';
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function buildProfileRegionBody(values) {
var source = values || {};
return {
provinceCode: trimOrUndefined(source.provinceCode),
cityCode: trimOrUndefined(source.cityCode),
districtCode: trimOrUndefined(source.districtCode)
};
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
function setOptions(select, items, placeholder) {
var list = normalizeList(items);
if (!select) return;
select.innerHTML = '<option value="">' + escapeHtml(placeholder) + '</option>' + list.map(buildRegionOption).join('');
select.disabled = false;
}
function resetSelect(select, placeholder) {
if (!select) return;
select.innerHTML = '<option value="">' + escapeHtml(placeholder) + '</option>';
select.disabled = true;
}
function updateTargetCode(picker) {
var values = {
provinceCode: query('[data-region-level="province"]', picker).value,
cityCode: query('[data-region-level="city"]', picker).value,
districtCode: query('[data-region-level="district"]', picker).value
};
var target = query('[data-region-code]', picker);
if (target) target.value = getFinalRegionCode(values);
}
async function loadChildrenInto(select, parentCode, placeholder) {
var api = getApi();
if (!api || !select) return;
setOptions(select, await api.regionChildren(parentCode || '0'), placeholder);
}
async function initPicker(picker) {
var province = query('[data-region-level="province"]', picker);
var city = query('[data-region-level="city"]', picker);
var district = query('[data-region-level="district"]', picker);
resetSelect(city, '请选择市');
resetSelect(district, '请选择区县');
await loadChildrenInto(province, '0', '请选择省');
province.addEventListener('change', async function () {
resetSelect(city, '请选择市');
resetSelect(district, '请选择区县');
updateTargetCode(picker);
if (province.value) await loadChildrenInto(city, province.value, '请选择市');
});
city.addEventListener('change', async function () {
resetSelect(district, '请选择区县');
updateTargetCode(picker);
if (city.value) await loadChildrenInto(district, city.value, '请选择区县');
});
district.addEventListener('change', function () {
updateTargetCode(picker);
});
}
async function submitProfileRegion(form) {
var api = getApi();
var values = getFormValues(form);
var body = buildProfileRegionBody(values);
if (!api) return;
if (!body.provinceCode) {
showMessage('请选择省份');
return;
}
try {
await api.updateProfile(body);
showMessage('地区资料已保存');
} catch (error) {
showMessage(error.message || '地区资料保存失败');
}
}
function bindProfileForms() {
queryAll('[data-region-profile-form]').forEach(function (form) {
form.addEventListener('submit', function (event) {
event.preventDefault();
submitProfileRegion(form);
});
});
}
function init() {
if (!documentRef) return;
queryAll('[data-region-picker]').forEach(function (picker) {
initPicker(picker);
});
bindProfileForms();
}
return {
normalizeList: normalizeList,
buildRegionOption: buildRegionOption,
buildPathText: buildPathText,
getFinalRegionCode: getFinalRegionCode,
buildProfileRegionBody: buildProfileRegionBody,
init: init
};
});
+93
View File
@@ -0,0 +1,93 @@
(function (window, $) {
'use strict';
var defaultItems = [
'source', '|',
'undo', 'redo', '|',
'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
'plainpaste', 'wordpaste', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyfull',
'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', '|',
'formatblock', 'fontname', 'fontsize', '|',
'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
'strikethrough', 'lineheight', 'removeformat', '|',
'image', 'multiimage', 'table', 'hr', 'emoticons', 'baidumap',
'pagebreak', 'anchor', 'link', 'unlink', '|',
'about'
];
function getJquery() {
return $ || window.jQuery || (window.layui && window.layui.$);
}
function normalizeSelector(target) {
var jq = getJquery();
if (!target) return '';
if (typeof target === 'string') return target;
if (jq && target instanceof jq) target = target.get(0);
if (target && target.id) return '#' + target.id;
return target;
}
function initRichEditor(target, options) {
var jq = getJquery();
var selector = normalizeSelector(target);
var $textarea;
if (!jq) return null;
$textarea = jq(selector).first();
if (!$textarea.length || !window.KindEditor) return null;
if (!$textarea.attr('id')) {
$textarea.attr('id', 'rich-editor-' + Math.floor(Math.random() * 1000000));
selector = '#' + $textarea.attr('id');
}
return window.KindEditor.create(selector, jq.extend({
width: '100%',
minWidth: '100%',
height: '460px',
resizeType: 1,
allowPreviewEmoticons: true,
allowImageUpload: true,
filterMode: false,
newlineTag: 'p',
items: defaultItems,
afterBlur: function () {
this.sync();
}
}, options || {}));
}
function initRichEditors(root, options) {
var jq = getJquery();
var editors = {};
var $root;
if (!jq) return editors;
$root = root ? jq(root) : jq(document);
$root.find('.js-rich-editor').each(function (index) {
var $textarea = jq(this);
var id = $textarea.attr('id') || ('rich-editor-' + (index + 1));
$textarea.attr('id', id);
editors[id] = initRichEditor('#' + id, options);
});
return editors;
}
window.AppRichEditor = {
init: initRichEditor,
initAll: initRichEditors
};
if (getJquery()) {
getJquery()(function () {
if (getJquery()('.js-rich-editor').length) {
initRichEditors(document);
}
});
}
})(window, window.jQuery || (window.layui && window.layui.$));
+254
View File
@@ -0,0 +1,254 @@
(function (root, factory) {
// 账号安全模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.SecurityPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.SecurityPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function hashPassword(value) {
// 接口文档要求密码提交 32 位 MD5,测试环境可传入 hashFn 替代。
if (root.hex_md5) return root.hex_md5(value);
if (root.md5) return root.md5(value);
return value;
}
function trimOrUndefined(value) {
var text = String(value === undefined || value === null ? '' : value).trim();
return text || undefined;
}
function buildPasswordChangeBody(values, hashFn) {
var source = values || {};
var hash = hashFn || hashPassword;
return {
oldPassword: hash(String(source.oldPassword || '').trim()),
newPassword: hash(String(source.newPassword || '').trim())
};
}
function buildPhoneChangeBody(values) {
var source = values || {};
return {
newPhone: String(source.newPhone || '').trim(),
smsCode: String(source.smsCode || '').trim(),
validToken: trimOrUndefined(source.validToken)
};
}
function buildSmsLoginBody(values) {
var source = values || {};
return {
phone: String(source.phone || '').trim(),
smsCode: String(source.smsCode || '').trim(),
validToken: trimOrUndefined(source.validToken)
};
}
function buildDeactivateBody(values, hashFn) {
var source = values || {};
var hash = hashFn || hashPassword;
return {
password: hash(String(source.password || '').trim()),
reason: trimOrUndefined(source.reason)
};
}
function isDangerConfirmed(value) {
return String(value || '').trim() === '确认注销';
}
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function queryAll(selector, rootNode) {
return Array.prototype.slice.call((rootNode || documentRef).querySelectorAll(selector));
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function getFormValues(form) {
var values = {};
queryAll('[name]', form).forEach(function (field) {
values[field.name] = field.value;
});
return values;
}
function setStatus(form, message) {
var status = query('[data-security-status]', form);
if (status) status.textContent = message;
}
async function submitPassword(form) {
var api = getApi();
var values = getFormValues(form);
if (!api) return;
if (!values.oldPassword || !values.newPassword) {
showMessage('请填写原密码和新密码');
return;
}
if (values.newPassword !== values.confirmPassword) {
showMessage('两次新密码不一致');
return;
}
try {
await api.changePassword(buildPasswordChangeBody(values));
setStatus(form, '密码已修改');
showMessage('密码已修改');
form.reset();
} catch (error) {
showMessage(error.message || '密码修改失败');
}
}
async function submitPhone(form) {
var api = getApi();
var body = buildPhoneChangeBody(getFormValues(form));
if (!api) return;
if (!body.newPhone || !body.smsCode) {
showMessage('请填写新手机号和验证码');
return;
}
try {
await api.changePhone(body);
setStatus(form, '手机号已换绑');
showMessage('手机号已换绑');
form.reset();
} catch (error) {
showMessage(error.message || '手机号换绑失败');
}
}
async function submitSmsLogin(form) {
var api = getApi();
var body = buildSmsLoginBody(getFormValues(form));
if (!api) return;
if (!body.phone || !body.smsCode) {
showMessage('请填写手机号和验证码');
return;
}
try {
await api.smsLogin(body);
setStatus(form, '短信登录已通过');
showMessage('短信登录已通过');
} catch (error) {
showMessage(error.message || '短信登录失败');
}
}
async function submitDeactivate(form) {
var api = getApi();
var values = getFormValues(form);
if (!api) return;
if (!values.password) {
showMessage('请填写当前密码');
return;
}
if (!isDangerConfirmed(values.confirmText)) {
showMessage('请完整输入“确认注销”');
return;
}
if (root.confirm && !root.confirm('账号注销后将退出登录,确认继续?')) return;
try {
await api.deactivateAccount(buildDeactivateBody(values));
showMessage('账号已提交注销');
root.location.href = 'login.html';
} catch (error) {
showMessage(error.message || '账号注销失败');
}
}
async function logout() {
var api = getApi();
if (!api) return;
if (root.confirm && !root.confirm('确认退出当前账号?')) return;
try {
await api.logout();
root.location.href = 'login.html';
} catch (error) {
showMessage(error.message || '退出登录失败');
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('submit', function (event) {
var form = event.target.closest('[data-security-form]');
var formType;
if (!form) return;
event.preventDefault();
formType = form.getAttribute('data-security-form');
if (formType === 'password') submitPassword(form);
if (formType === 'phone') submitPhone(form);
if (formType === 'sms-login') submitSmsLogin(form);
if (formType === 'deactivate') submitDeactivate(form);
});
documentRef.addEventListener('click', function (event) {
var button = event.target.closest('[data-security-logout]');
if (!button) return;
event.preventDefault();
logout();
});
}
function init() {
if (!documentRef || !query('[data-security-page]')) return;
bindActions();
}
return {
buildPasswordChangeBody: buildPasswordChangeBody,
buildPhoneChangeBody: buildPhoneChangeBody,
buildSmsLoginBody: buildSmsLoginBody,
buildDeactivateBody: buildDeactivateBody,
isDangerConfirmed: isDangerConfirmed,
init: init
};
});
+132
View File
@@ -0,0 +1,132 @@
(function (root, factory) {
// 公共上传模块同时支持浏览器页面和 Node 单元测试。
if (typeof module === 'object' && module.exports) {
module.exports = factory(root);
return;
}
root.UploadPages = factory(root);
if (root.document) {
root.document.addEventListener('DOMContentLoaded', function () {
root.UploadPages.init();
});
}
})(typeof globalThis !== 'undefined' ? globalThis : window, function (root) {
'use strict';
var documentRef = root.document;
function getApi() {
return root.GenealogyApi && root.GenealogyApi.defaultClient;
}
function query(selector, rootNode) {
return (rootNode || documentRef).querySelector(selector);
}
function showMessage(message) {
if (root.layui && root.layui.layer) {
root.layui.layer.msg(message);
return;
}
root.alert(message);
}
function pick(item, keys, fallback) {
var source = item || {};
var index;
var value;
for (index = 0; index < keys.length; index += 1) {
value = source[keys[index]];
if (value !== undefined && value !== null && value !== '') return value;
}
return fallback || '';
}
function normalizeUploadResult(data) {
// FileUploadResult 字段可能因后端实现不同而略有差异,这里只收敛页面需要的值。
var source = data || {};
var ossId = pick(source, ['ossId', 'id', 'fileId', 'oss_id'], '');
var fileName = pick(source, ['fileName', 'originalName', 'name'], '');
var url = pick(source, ['url', 'fileUrl', 'previewUrl'], '');
return {
ossId: String(ossId || ''),
fileName: String(fileName || ''),
url: String(url || '')
};
}
function mergeOssIds(currentValue, nextValue, multiple) {
var next = String(nextValue || '').trim();
var current = String(currentValue || '').trim();
var values;
if (!next) return current;
if (!multiple) return next;
values = current ? current.split(',').map(function (item) {
return item.trim();
}).filter(Boolean) : [];
if (values.indexOf(next) === -1) values.push(next);
return values.join(',');
}
function buildUploadStatus(fileName, ossId) {
return (fileName || '文件') + ' 上传完成,OSS ID' + ossId;
}
async function uploadFromInput(input) {
var api = getApi();
var file = input.files && input.files[0];
var targetSelector = input.getAttribute('data-upload-target');
var statusSelector = input.getAttribute('data-upload-status');
var target = targetSelector && query(targetSelector);
var status = statusSelector && query(statusSelector);
var multiple = input.getAttribute('data-upload-multiple') === 'true';
var result;
if (!api || !file || !target) return;
if (status) status.textContent = '上传中...';
input.disabled = true;
try {
result = normalizeUploadResult(await api.uploadFile(file));
if (!result.ossId) throw new Error('上传结果缺少 OSS ID');
target.value = mergeOssIds(target.value, result.ossId, multiple);
if (status) status.textContent = buildUploadStatus(result.fileName || file.name, result.ossId);
showMessage('文件上传完成');
} catch (error) {
if (status) status.textContent = error.message || '上传失败';
showMessage(error.message || '上传失败');
} finally {
input.disabled = false;
input.value = '';
}
}
function bindActions() {
if (!documentRef) return;
documentRef.addEventListener('change', function (event) {
var input = event.target.closest('[data-upload-target]');
if (!input || input.type !== 'file') return;
uploadFromInput(input);
});
}
function init() {
bindActions();
}
return {
normalizeUploadResult: normalizeUploadResult,
mergeOssIds: mergeOssIds,
buildUploadStatus: buildUploadStatus,
init: init
};
});

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