|
|
@@ -1,412 +0,0 @@
|
|
|
-(function($) {
|
|
|
- $.fn.smartDropdown = function(options) {
|
|
|
- const settings = $.extend({
|
|
|
- url: '',
|
|
|
- method: 'GET',
|
|
|
- valueField: 'id',
|
|
|
- textField: 'name',
|
|
|
- placeholder: '请选择',
|
|
|
- searchPlaceholder: '搜索...',
|
|
|
- minSearchLength: 1,
|
|
|
- searchDelay: 300,
|
|
|
- pageSize: 10,
|
|
|
- params: {},
|
|
|
- contentType: 'application/json', // 新增:内容类型配置
|
|
|
- processData: true, // 新增:是否处理数据
|
|
|
- onSelect: null,
|
|
|
- onLoad: null,
|
|
|
- formatResult: null,
|
|
|
- formatPagination: null
|
|
|
- }, options);
|
|
|
-
|
|
|
- return this.each(function() {
|
|
|
- const $container = $(this);
|
|
|
- let currentPage = 1;
|
|
|
- let searchQuery = '';
|
|
|
- let timer = null;
|
|
|
- let selectedValue = null;
|
|
|
- let selectedText = '';
|
|
|
- let dataCache = {};
|
|
|
-
|
|
|
- // 初始化结构(保持不变)
|
|
|
- $container.addClass('smart-dropdown');
|
|
|
- $container.html(`
|
|
|
- <input type="text" class="smart-dropdown-input" readonly placeholder="${settings.placeholder}">
|
|
|
- <div class="smart-dropdown-arrow">▼</div>
|
|
|
- <div class="smart-dropdown-menu">
|
|
|
- <div class="smart-dropdown-search">
|
|
|
- <input type="text" class="smart-search-input" placeholder="${settings.searchPlaceholder}">
|
|
|
- </div>
|
|
|
- <div class="smart-dropdown-content"></div>
|
|
|
- <div class="smart-dropdown-pagination">
|
|
|
- <div class="smart-pagination-info"></div>
|
|
|
- <div class="smart-pagination-controls">
|
|
|
- <button class="smart-page-prev">上一页</button>
|
|
|
- <button class="smart-page-next">下一页</button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- `);
|
|
|
-
|
|
|
- const $input = $container.find('.smart-dropdown-input');
|
|
|
- const $arrow = $container.find('.smart-dropdown-arrow');
|
|
|
- const $menu = $container.find('.smart-dropdown-menu');
|
|
|
- const $searchInput = $container.find('.smart-search-input');
|
|
|
- const $content = $container.find('.smart-dropdown-content');
|
|
|
- const $prevBtn = $container.find('.smart-page-prev');
|
|
|
- const $nextBtn = $container.find('.smart-page-next');
|
|
|
- const $paginationInfo = $container.find('.smart-pagination-info');
|
|
|
-
|
|
|
- // 构建请求参数
|
|
|
- function buildRequestParams(page) {
|
|
|
- const baseParams = {
|
|
|
- pageNo: page,
|
|
|
- pageRows: settings.pageSize
|
|
|
- };
|
|
|
-
|
|
|
- // 添加搜索条件
|
|
|
- if (searchQuery) {
|
|
|
- baseParams.search = searchQuery;
|
|
|
- baseParams.keyword = searchQuery; // 兼容不同后端参数名
|
|
|
- }
|
|
|
-
|
|
|
- // 合并自定义参数
|
|
|
- $.extend(baseParams, settings.params);
|
|
|
-
|
|
|
- return baseParams;
|
|
|
- }
|
|
|
-
|
|
|
- // 将参数转换为字符串(根据contentType)
|
|
|
- function prepareRequestData(params) {
|
|
|
- const method = settings.method.toUpperCase();
|
|
|
- const contentType = settings.contentType.toLowerCase();
|
|
|
-
|
|
|
- if (method === 'GET') {
|
|
|
- return params;
|
|
|
- }
|
|
|
-
|
|
|
- if (contentType.includes('application/json')) {
|
|
|
- // JSON格式
|
|
|
- return JSON.stringify(params);
|
|
|
- } else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
|
- // URL编码格式
|
|
|
- return $.param(params);
|
|
|
- } else if (contentType.includes('multipart/form-data')) {
|
|
|
- // FormData格式
|
|
|
- const formData = new FormData();
|
|
|
- Object.keys(params).forEach(key => {
|
|
|
- formData.append(key, params[key]);
|
|
|
- });
|
|
|
- return formData;
|
|
|
- }
|
|
|
-
|
|
|
- // 默认使用URL编码
|
|
|
- return $.param(params);
|
|
|
- }
|
|
|
-
|
|
|
- // 加载数据
|
|
|
- function loadData(page) {
|
|
|
- currentPage = page;
|
|
|
-
|
|
|
- // 构建请求参数
|
|
|
- const requestParams = buildRequestParams(page);
|
|
|
-
|
|
|
- // 检查缓存
|
|
|
- const cacheKey = JSON.stringify({
|
|
|
- params: requestParams,
|
|
|
- method: settings.method,
|
|
|
- contentType: settings.contentType
|
|
|
- });
|
|
|
-
|
|
|
- if (dataCache[cacheKey]) {
|
|
|
- renderData(dataCache[cacheKey]);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- showLoading();
|
|
|
-
|
|
|
- // 准备请求数据
|
|
|
- const requestData = prepareRequestData(requestParams);
|
|
|
-
|
|
|
- // 构建请求配置
|
|
|
- const requestConfig = {
|
|
|
- url: settings.url,
|
|
|
- type: settings.method.toUpperCase(),
|
|
|
- dataType: 'json',
|
|
|
- contentType: settings.contentType,
|
|
|
- processData: settings.processData,
|
|
|
- data: requestData
|
|
|
- };
|
|
|
-
|
|
|
- // 特殊处理:如果是FormData,需要设置processData和contentType为false
|
|
|
- if (requestData instanceof FormData) {
|
|
|
- requestConfig.processData = false;
|
|
|
- requestConfig.contentType = false;
|
|
|
- }
|
|
|
-
|
|
|
- // 特殊处理:如果是GET请求,参数放在URL中
|
|
|
- if (settings.method.toUpperCase() === 'GET') {
|
|
|
- requestConfig.data = requestParams;
|
|
|
- }
|
|
|
-
|
|
|
- console.log('请求配置:', requestConfig); // 调试用
|
|
|
-
|
|
|
- // 发送请求
|
|
|
- $.ajax(requestConfig)
|
|
|
- .done(function(response) {
|
|
|
- if(response.data){
|
|
|
- console.log(response)
|
|
|
- }
|
|
|
- if(response.data.dataList !== undefined || response.data.list !== undefined){
|
|
|
- console.log(1)
|
|
|
- }
|
|
|
- if (response.data && (response.data.dataList !== undefined || response.data.list !== undefined)) {
|
|
|
- // 标准化响应数据
|
|
|
- const normalizedResponse = normalizeResponse(response.data);
|
|
|
-
|
|
|
- // 缓存数据
|
|
|
- dataCache[cacheKey] = normalizedResponse;
|
|
|
-
|
|
|
- // 渲染数据
|
|
|
- renderData(normalizedResponse);
|
|
|
-
|
|
|
- // 触发加载回调
|
|
|
- if (typeof settings.onLoad === 'function') {
|
|
|
- settings.onLoad(normalizedResponse);
|
|
|
- }
|
|
|
- } else {
|
|
|
- showError('数据格式错误');
|
|
|
- }
|
|
|
- })
|
|
|
- .fail(function(jqXHR, textStatus, errorThrown) {
|
|
|
- console.error('请求失败:', jqXHR, textStatus, errorThrown);
|
|
|
- showError(`加载失败: ${textStatus}`);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- // 标准化响应数据(兼容不同后端格式)
|
|
|
- function normalizeResponse(response) {
|
|
|
- // 如果已经是标准格式,直接返回
|
|
|
- if (response.dataList && response.pageNo !== undefined) {
|
|
|
- return response;
|
|
|
- }
|
|
|
-
|
|
|
- // 尝试从常见格式转换
|
|
|
- const normalized = {
|
|
|
- pageNo: currentPage,
|
|
|
- pageRows: settings.pageSize,
|
|
|
- pageCount: 1,
|
|
|
- totalRows: 0,
|
|
|
- dataList: []
|
|
|
- };
|
|
|
-
|
|
|
- // 检查常见的数据字段名
|
|
|
- const dataFields = ['dataList', 'list', 'items', 'data', 'rows', 'records'];
|
|
|
- const countFields = ['totalRows', 'total', 'totalCount', 'count', 'totalRecords'];
|
|
|
- const pageFields = ['pageCount', 'totalPages', 'pages'];
|
|
|
-
|
|
|
- // 查找数据列表
|
|
|
- for (const field of dataFields) {
|
|
|
- if (response[field] && Array.isArray(response[field])) {
|
|
|
- normalized.dataList = response[field];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 查找总记录数
|
|
|
- for (const field of countFields) {
|
|
|
- if (response[field] !== undefined) {
|
|
|
- normalized.totalRows = response[field];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 查找总页数
|
|
|
- for (const field of pageFields) {
|
|
|
- if (response[field] !== undefined) {
|
|
|
- normalized.pageCount = response[field];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果没有找到总页数,根据总记录数计算
|
|
|
- if (normalized.pageCount === 1 && normalized.totalRows > 0) {
|
|
|
- normalized.pageCount = Math.ceil(normalized.totalRows / settings.pageSize);
|
|
|
- }
|
|
|
-
|
|
|
- return normalized;
|
|
|
- }
|
|
|
-
|
|
|
- // 其他函数保持不变...
|
|
|
- function showLoading() {
|
|
|
- $content.html('<div class="loading">加载中...</div>');
|
|
|
- $prevBtn.prop('disabled', true);
|
|
|
- $nextBtn.prop('disabled', true);
|
|
|
- }
|
|
|
-
|
|
|
- function showError(message) {
|
|
|
- $content.html(`<div class="error">${message}</div>`);
|
|
|
- $paginationInfo.text('');
|
|
|
- }
|
|
|
-
|
|
|
- function renderData(data) {
|
|
|
- const items = data.dataList || [];
|
|
|
- const pageCount = data.pageCount || 1;
|
|
|
- const totalRows = data.totalRows || 0;
|
|
|
- const currentRows = items.length;
|
|
|
-
|
|
|
- // 渲染列表项
|
|
|
- let html = '';
|
|
|
- if (items.length > 0) {
|
|
|
- items.forEach(function(item) {
|
|
|
- const value = item[settings.valueField];
|
|
|
- const text = item[settings.textField] || '';
|
|
|
- const isSelected = (value == selectedValue);
|
|
|
-
|
|
|
- let itemHtml = '';
|
|
|
- if (typeof settings.formatResult === 'function') {
|
|
|
- itemHtml = settings.formatResult(item, isSelected);
|
|
|
- } else {
|
|
|
- const selectedClass = isSelected ? 'selected' : '';
|
|
|
- itemHtml = `<div class="smart-dropdown-item ${selectedClass}"
|
|
|
- data-value="${value}"
|
|
|
- data-text="${text}">${text}</div>`;
|
|
|
- }
|
|
|
- html += itemHtml;
|
|
|
- });
|
|
|
- } else {
|
|
|
- html = '<div class="loading">暂无数据</div>';
|
|
|
- }
|
|
|
-
|
|
|
- $content.html(html);
|
|
|
-
|
|
|
- // 渲染分页信息
|
|
|
- let paginationText = '';
|
|
|
- if (typeof settings.formatPagination === 'function') {
|
|
|
- paginationText = settings.formatPagination(data);
|
|
|
- } else {
|
|
|
- const start = (data.pageNo - 1) * settings.pageSize + 1;
|
|
|
- const end = start + currentRows - 1;
|
|
|
- //paginationText = `显示 ${start}-${end} 条,共 ${totalRows} 条`;
|
|
|
- paginationText = `第${data.pageNo}页,共${data.pageCount}页`;
|
|
|
- }
|
|
|
-
|
|
|
- $paginationInfo.text(paginationText);
|
|
|
-
|
|
|
- // 更新分页按钮状态
|
|
|
- $prevBtn.prop('disabled', data.pageNo <= 1);
|
|
|
- $nextBtn.prop('disabled', data.pageNo >= pageCount);
|
|
|
- }
|
|
|
-
|
|
|
- function selectItem(value, text) {
|
|
|
- selectedValue = value;
|
|
|
- selectedText = text;
|
|
|
- $input.val(text);
|
|
|
-
|
|
|
- if (typeof settings.onSelect === 'function') {
|
|
|
- settings.onSelect({
|
|
|
- value: value,
|
|
|
- text: text,
|
|
|
- rawValue: selectedValue,
|
|
|
- rawText: selectedText
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- closeMenu();
|
|
|
- }
|
|
|
-
|
|
|
- // 事件绑定(保持不变)...
|
|
|
- $input.on('click', toggleMenu);
|
|
|
- $arrow.on('click', toggleMenu);
|
|
|
-
|
|
|
- $searchInput.on('input', function() {
|
|
|
- const query = $(this).val().trim();
|
|
|
-
|
|
|
- clearTimeout(timer);
|
|
|
- timer = setTimeout(function() {
|
|
|
- if (query.length >= settings.minSearchLength || query === '') {
|
|
|
- searchQuery = query;
|
|
|
- dataCache = {}; // 清空缓存
|
|
|
- loadData(1);
|
|
|
- }
|
|
|
- }, settings.searchDelay);
|
|
|
- });
|
|
|
-
|
|
|
- $content.on('click', '.smart-dropdown-item', function() {
|
|
|
- const value = $(this).data('value');
|
|
|
- const text = $(this).data('text');
|
|
|
- selectItem(value, text);
|
|
|
- });
|
|
|
-
|
|
|
- $prevBtn.on('click', function() {
|
|
|
- if (!$(this).prop('disabled')) {
|
|
|
- loadData(currentPage - 1);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- $nextBtn.on('click', function() {
|
|
|
- if (!$(this).prop('disabled')) {
|
|
|
- loadData(currentPage + 1);
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- $(document).on('click', function(event) {
|
|
|
- if (!$container.is(event.target) && $container.has(event.target).length === 0) {
|
|
|
- closeMenu();
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- function toggleMenu() {
|
|
|
- if ($menu.is(':visible')) {
|
|
|
- closeMenu();
|
|
|
- } else {
|
|
|
- openMenu();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function openMenu() {
|
|
|
- if (!$menu.is(':visible')) {
|
|
|
- $menu.show();
|
|
|
- $searchInput.focus();
|
|
|
- loadData(1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function closeMenu() {
|
|
|
- $menu.hide();
|
|
|
- }
|
|
|
-
|
|
|
- // 公共方法
|
|
|
- $container.data('smartDropdown', {
|
|
|
- getValue: function() {
|
|
|
- return selectedValue;
|
|
|
- },
|
|
|
- getText: function() {
|
|
|
- return selectedText;
|
|
|
- },
|
|
|
- setValue: function(value, text) {
|
|
|
- selectedValue = value;
|
|
|
- selectedText = text || '';
|
|
|
- $input.val(selectedText);
|
|
|
- },
|
|
|
- clear: function() {
|
|
|
- selectedValue = null;
|
|
|
- selectedText = '';
|
|
|
- $input.val('');
|
|
|
- },
|
|
|
- refresh: function() {
|
|
|
- dataCache = {};
|
|
|
- loadData(1);
|
|
|
- },
|
|
|
- open: openMenu,
|
|
|
- close: closeMenu,
|
|
|
- setSearch: function(query) {
|
|
|
- searchQuery = query;
|
|
|
- $searchInput.val(query);
|
|
|
- dataCache = {};
|
|
|
- loadData(1);
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
- };
|
|
|
-})(jQuery);
|