define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'backend/format'], function ($, undefined, Backend, Table, Form, Format) { var Controller = { /** * 服务区域列表页初始化 */ index: function () { // 初始化表格参数配置 Table.api.init({ extend: { index_url: 'fc/area/index' + location.search, add_url: 'fc/area/add', edit_url: 'fc/area/edit', del_url: 'fc/area/del', multi_url: 'fc/area/multi', import_url: 'fc/area/import', table: 'fc_area', } }); var table = $("#table"); // 初始化表格 table.bootstrapTable({ url: $.fn.bootstrapTable.defaults.extend.index_url, pk: 'id', sortName: 'sort', columns: [ [ {checkbox: true}, {field: 'id', title: __('SerialNo'), operate: false, sortable: false, align: 'center', width: '70px', class: 'fc-serial', table: table, formatter: Format.serial}, {field: 'province', title: __('Province'), operate: 'LIKE'}, {field: 'city', title: __('City'), operate: 'LIKE'}, {field: 'district', title: __('District'), operate: 'LIKE'}, {field: 'full_name', title: __('FullName'), operate: false, sortable: false}, { field: 'enabled', title: __('Enabled'), searchList: {0: '否', 1: '是'}, formatter: Format.statusFormatter({0: '否', 1: '是'}, {0: 'default', 1: 'success'}) }, {field: 'sort', title: __('Sort'), width: '80px'}, {field: 'lat', title: __('Lat'), operate: false, visible: false}, {field: 'lng', title: __('Lng'), operate: false, visible: false}, {field: 'createtime', title: __('Createtime'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime}, {field: 'updatetime', title: __('Updatetime'), operate: 'RANGE', addclass: 'datetimerange', autocomplete: false, formatter: Table.api.formatter.datetime, visible: false}, {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} ] ] }); // 为表格绑定事件 Table.api.bindevent(table); }, /** * 服务区域新增页初始化 */ add: function () { Controller.api.bindevent(); Controller.api.bindAreaOptions(); }, /** * 服务区域编辑页初始化 */ edit: function () { Controller.api.bindevent(); Controller.api.bindAreaOptions(); }, api: { /** * 绑定表单通用事件 */ bindevent: function () { Form.api.bindevent($("form[role=form]")); }, /** * 规范化省级名称(将直辖市简称统一为标准全称) * @param {string} name 原始省份名称 * @return {string} */ normalizeProvinceName: function (name) { var val = String(name || '').trim(); var map = { '北京': '北京市', '天津': '天津市', '上海': '上海市', '重庆': '重庆市', '台湾': '台湾省' }; return map[val] || val; }, /** * 加载全国行政区划数据(ChineseDistricts) * @param {function} callback 数据加载完成回调 */ loadNationalDistricts: function (callback) { if (typeof window !== 'undefined' && window.ChineseDistricts) { callback(window.ChineseDistricts); return; } require(['citypicker-data'], function () { if (typeof window !== 'undefined' && window.ChineseDistricts) { callback(window.ChineseDistricts); return; } require(['ChineseDistricts'], function (ChineseDistricts) { callback(ChineseDistricts || window.ChineseDistricts || {}); }, function () { callback({}); }); }, function () { callback({}); }); }, /** * 构建全国省 / 市 / 区县全量数据树并合并数据库已有记录 * @param {Object} chineseDistricts 全国行政区划原始字典 * @param {Array} dbRows 数据库已存服务区域记录 * @param {number} currentId 当前编辑记录ID(新增时为0) * @return {Object} 包含 provinces, cityMap, districtMap, allCities, allDistricts, addedMap */ buildAreaDataTree: function (chineseDistricts, dbRows, currentId) { var normalizeProvince = Controller.api.normalizeProvinceName; var provinces = []; var provinceSeen = {}; var cityMap = {}; var districtMap = {}; var addedMap = {}; /** * 确保省份存在于数据树中 * @param {string} prov 省份名称 */ var ensureProvince = function (prov) { var p = normalizeProvince(prov); if (!p) { return ''; } if (!provinceSeen[p]) { provinceSeen[p] = true; provinces.push(p); } if (!cityMap[p]) { cityMap[p] = []; } return p; }; /** * 确保城市存在于指定省份下 * @param {string} prov 省份名称 * @param {string} city 城市名称 */ var ensureCity = function (prov, city) { var p = ensureProvince(prov); var c = String(city || '').trim(); if (!p || !c) { return; } if (cityMap[p].indexOf(c) === -1) { cityMap[p].push(c); } var key = p + '|' + c; if (!districtMap[key]) { districtMap[key] = []; } }; /** * 确保区县存在于指定省市下 * @param {string} prov 省份名称 * @param {string} city 城市名称 * @param {string} dist 区县名称 */ var ensureDistrict = function (prov, city, dist) { var p = ensureProvince(prov); var c = String(city || '').trim(); var d = String(dist || '').trim(); if (!p || !c || !d) { return; } ensureCity(p, c); var key = p + '|' + c; if (districtMap[key].indexOf(d) === -1) { districtMap[key].push(d); } }; // 1. 解析全国行政区划库 ChineseDistricts if (chineseDistricts && chineseDistricts[86]) { var groups = chineseDistricts[86]; var provEntries = []; $.each(groups, function (groupKey, list) { if ($.isArray(list)) { for (var i = 0; i < list.length; i++) { if (list[i] && list[i].code && list[i].address) { provEntries.push(list[i]); } } } }); // 按行政区划代码排序(北京、天津、河北...顺序更符合国标习惯) provEntries.sort(function (a, b) { return String(a.code).localeCompare(String(b.code)); }); for (var i = 0; i < provEntries.length; i++) { var provCode = provEntries[i].code; var provName = ensureProvince(provEntries[i].address); var citiesObj = chineseDistricts[provCode]; if (citiesObj && $.isPlainObject(citiesObj)) { $.each(citiesObj, function (cityCode, cityName) { ensureCity(provName, cityName); var districtsObj = chineseDistricts[cityCode]; if (districtsObj && $.isPlainObject(districtsObj)) { $.each(districtsObj, function (distCode, distName) { ensureDistrict(provName, cityName, distName); }); } }); } } } // 2. 合并数据库已有的 fc_area 记录(兼顾自定义区域与已添加标记) if ($.isArray(dbRows)) { for (var j = 0; j < dbRows.length; j++) { var row = dbRows[j] || {}; var pRaw = String(row.province || '').trim(); var pNorm = normalizeProvince(pRaw); var cName = String(row.city || '').trim(); var dName = String(row.district || '').trim(); var rowId = parseInt(row.id || 0, 10); if (pNorm && cName && dName) { ensureDistrict(pNorm, cName, dName); if (rowId !== currentId) { addedMap[pNorm + '|' + cName + '|' + dName] = true; addedMap[pRaw + '|' + cName + '|' + dName] = true; } } } } // 3. 构建全国扁平化城市索引与区县索引,支持跨省直搜城市/区县反填 var allCities = []; var allDistricts = []; for (var pIdx = 0; pIdx < provinces.length; pIdx++) { var pItem = provinces[pIdx]; var cList = cityMap[pItem] || []; for (var cIdx = 0; cIdx < cList.length; cIdx++) { var cItem = cList[cIdx]; allCities.push({ province: pItem, city: cItem }); var dList = districtMap[pItem + '|' + cItem] || []; for (var dIdx = 0; dIdx < dList.length; dIdx++) { allDistricts.push({ province: pItem, city: cItem, district: dList[dIdx] }); } } } return { provinces: provinces, cityMap: cityMap, districtMap: districtMap, allCities: allCities, allDistricts: allDistricts, addedMap: addedMap }; }, /** * 省 / 市 / 区县全量可搜索级联下拉与中心坐标联动 */ bindAreaOptions: function () { var $raw = $('#area-options'); var $province = $('#c-province'); var $city = $('#c-city'); var $district = $('#c-district'); var $lat = $('#c-lat'); var $lng = $('#c-lng'); if (!$raw.length || !$province.length) { return; } var currentId = parseInt($raw.data('current-id') || 0, 10); var dbRows = []; try { dbRows = JSON.parse($raw.val() || '[]'); } catch (e) { dbRows = []; } if (!$.isArray(dbRows)) { dbRows = []; } var normalizeProvince = Controller.api.normalizeProvinceName; var coordAutoFilled = false; var geocodeTimer = null; /** * 更新输入框包装容器的 has-value 状态(控制清空按钮显示) */ var syncWrapState = function () { $('.fc-area-select-wrap').each(function () { var $wrap = $(this); var val = String($wrap.find('.fc-area-input').val() || '').trim(); $wrap.toggleClass('has-value', val !== ''); }); }; /** * 将 WGS84 坐标转换为 GCJ02 坐标(中国大陆标准) * @param {number} wgsLng WGS84经度 * @param {number} wgsLat WGS84纬度 * @return {{lat: number, lng: number}} */ var wgs84ToGcj02 = function (wgsLng, wgsLat) { var lon = Number(wgsLng); var lat = Number(wgsLat); if (!isFinite(lon) || !isFinite(lat)) { return {lat: lat, lng: lon}; } var a = 6378245.0; var ee = 0.00669342162296594323; var pi = Math.PI; var 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 * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0; ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0; return ret; }; var 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 * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0; ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0; ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0; return ret; }; var dLat = transformLat(lon - 105.0, lat - 35.0); var dLon = transformLon(lon - 105.0, lat - 35.0); var radLat = lat / 180.0 * 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) * pi); dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi); return { lat: lat + dLat, lng: lon + dLon }; }; /** * 刷新完整区域实时预览文案并同步地图选点按钮默认地址 */ var refreshPreview = function () { var parts = [ String($province.val() || '').trim(), String($city.val() || '').trim(), String($district.val() || '').trim() ].filter(function (item) { return item !== ''; }); $('#area-full-name').text(parts.length ? parts.join(' / ') : '未选择'); $('.fc-area-map-btn').data('address', parts.join('')); syncWrapState(); }; /** * 刷新中心坐标状态提示文案 * @param {boolean} isAuto 是否为自动匹配填充 */ var refreshCoordTip = function (isAuto) { var lat = String($lat.val() || '').trim(); var lng = String($lng.val() || '').trim(); var $tip = $('#area-coord-tip'); if (lat && lng && isFinite(lat) && isFinite(lng)) { var prefix = isAuto ? '已根据所选区域自动匹配中心坐标:' : '已设置中心坐标:'; $tip.removeClass('is-missing').addClass('is-set') .text(prefix + lat + ', ' + lng + '(可点击「地图选点」微调)'); } else { $tip.removeClass('is-set').addClass('is-missing') .text('未设置坐标:选择区域后将自动匹配中心坐标,也可点击「地图选点」手动指定'); } }; /** * 根据所选省市区自动解析中心经纬度(腾讯Place接口 + Nominatim自动降级) */ var autoResolveCoordinates = function () { var p = String($province.val() || '').trim(); var c = String($city.val() || '').trim(); var d = String($district.val() || '').trim(); if (!p || !c || !d) { return; } var curLat = String($lat.val() || '').trim(); var curLng = String($lng.val() || '').trim(); // 若已有手动填写的坐标且非自动匹配产生,则不覆盖 if (curLat && curLng && !coordAutoFilled) { return; } if (geocodeTimer) { clearTimeout(geocodeTimer); } geocodeTimer = setTimeout(function () { var queryAddress = (p === c ? p : (p + ' ' + c)) + ' ' + d; var resolveByNominatim = function () { $.ajax({ url: 'https://nominatim.openstreetmap.org/search', dataType: 'jsonp', jsonp: 'json_callback', data: { format: 'json', q: queryAddress, limit: 1, 'accept-language': 'zh-CN', countrycodes: 'cn' }, success: function (list) { if ($.isArray(list) && list.length > 0 && list[0].lat && list[0].lon) { var gcj = wgs84ToGcj02(list[0].lon, list[0].lat); coordAutoFilled = true; $lat.val(Number(gcj.lat).toFixed(6)); $lng.val(Number(gcj.lng).toFixed(6)); refreshCoordTip(true); } } }); }; var tencentKey = 'WM7BZ-ZAYLL-MZEPZ-MRZBT-MBYJE-ZAFIT'; $.ajax({ url: 'https://apis.map.qq.com/ws/place/v1/suggestion', dataType: 'jsonp', data: { keyword: (p === c ? p : (p + c)) + d, region: c, key: tencentKey, output: 'jsonp' }, success: function (ret) { if (ret && ret.status === 0 && $.isArray(ret.data) && ret.data.length > 0 && ret.data[0].location) { var loc = ret.data[0].location; if (loc.lat && loc.lng) { coordAutoFilled = true; $lat.val(Number(loc.lat).toFixed(6)); $lng.val(Number(loc.lng).toFixed(6)); refreshCoordTip(true); return; } } resolveByNominatim(); }, error: function () { resolveByNominatim(); } }); }, 180); }; refreshPreview(); refreshCoordTip(false); // 手动修改坐标时标记为非自动填充 $lat.add($lng).on('input change', function () { coordAutoFilled = false; refreshCoordTip(false); }); // 加载全国省市区数据并绑定下拉交互 Controller.api.loadNationalDistricts(function (chineseDistricts) { var tree = Controller.api.buildAreaDataTree(chineseDistricts, dbRows, currentId); /** * 根据输入省份名称匹配标准省份键名 * @param {string} inputProv 输入的省份名 * @return {string} */ var resolveProvinceKey = function (inputProv) { var raw = String(inputProv || '').trim(); if (!raw) { return ''; } var norm = normalizeProvince(raw); if (tree.cityMap[norm]) { return norm; } for (var i = 0; i < tree.provinces.length; i++) { if (tree.provinces[i].indexOf(raw) !== -1 || raw.indexOf(tree.provinces[i].replace(/省|市|自治区|特别行政区|壮族|回族|维吾尔/g, '')) !== -1) { return tree.provinces[i]; } } return raw; }; /** * 关闭所有下拉面板 * @param {jQuery} [$exceptWrap] 排除不关闭的容器 */ var closeAllDropdowns = function ($exceptWrap) { $('.fc-area-select-wrap').each(function () { if (!$exceptWrap || !$(this).is($exceptWrap)) { $(this).removeClass('is-open'); } }); }; /** * 滚动下拉框使当前选中项可见 * @param {jQuery} $dropdown 下拉面板元素 */ var scrollActiveIntoView = function ($dropdown) { var $active = $dropdown.find('.fc-area-dropdown__item.is-active').first(); if ($active.length) { var top = $active.position().top + $dropdown.scrollTop() - 40; $dropdown.scrollTop(Math.max(0, top)); } else { $dropdown.scrollTop(0); } }; /** * 渲染省份下拉列表 * @param {boolean} filterByInput 是否根据当前输入内容过滤 */ var renderProvinceDropdown = function (filterByInput) { var $dropdown = $('#province-dropdown'); var currentVal = String($province.val() || '').trim(); var currentNorm = normalizeProvince(currentVal); var keyword = filterByInput ? currentVal.toLowerCase() : ''; var list = tree.provinces.filter(function (prov) { if (!keyword) { return true; } return prov.toLowerCase().indexOf(keyword) !== -1; }); $dropdown.empty(); $('
').text( keyword ? ('搜索省份(匹配 ' + list.length + ' 项)') : ('全国省级行政区(共 ' + tree.provinces.length + ' 个,可输入搜索)') ).appendTo($dropdown); if (!list.length) { $('
').text( '未找到匹配省份,可直接保存自定义省份「' + currentVal + '」' ).appendTo($dropdown); return; } for (var i = 0; i < list.length; i++) { var prov = list[i]; var cityCount = (tree.cityMap[prov] || []).length; var $item = $('
') .toggleClass('is-active', prov === currentVal || prov === currentNorm) .attr('data-province', prov); $('').text(prov).appendTo($item); if (cityCount > 0) { $('').text(cityCount + ' 个城市').appendTo($item); } $dropdown.append($item); } scrollActiveIntoView($dropdown); }; /** * 渲染城市下拉列表(支持按当前省份展示,或未选省份/跨省搜索时展示全国城市) * @param {boolean} filterByInput 是否根据当前输入内容过滤 */ var renderCityDropdown = function (filterByInput) { var $dropdown = $('#city-dropdown'); var provVal = resolveProvinceKey($province.val()); var currentCity = String($city.val() || '').trim(); var keyword = filterByInput ? currentCity.toLowerCase() : ''; $dropdown.empty(); var items = []; var isNationalMode = false; if (provVal && tree.cityMap[provVal] && !keyword) { // 已选省份且未输入搜索词:展示该省下全部城市 var provCities = tree.cityMap[provVal] || []; for (var i = 0; i < provCities.length; i++) { items.push({ province: provVal, city: provCities[i] }); } } else if (keyword) { // 输入了关键字:优先当前省份匹配,若无匹配或未选省份则检索全国城市 if (provVal && tree.cityMap[provVal]) { var pCities = tree.cityMap[provVal] || []; for (var j = 0; j < pCities.length; j++) { if (pCities[j].toLowerCase().indexOf(keyword) !== -1) { items.push({ province: provVal, city: pCities[j] }); } } } // 同时补充全国其他省份匹配的城市 isNationalMode = true; for (var k = 0; k < tree.allCities.length; k++) { var item = tree.allCities[k]; if (item.city.toLowerCase().indexOf(keyword) !== -1 || item.province.toLowerCase().indexOf(keyword) !== -1) { var exists = false; for (var m = 0; m < items.length; m++) { if (items[m].province === item.province && items[m].city === item.city) { exists = true; break; } } if (!exists) { items.push(item); } } } } else { // 未选省份:直接展示全国全部城市,点击自动带出所属省份 isNationalMode = true; items = tree.allCities.slice(0); } var headerText = ''; if (keyword) { headerText = '全国城市搜索结果(共 ' + items.length + ' 项,点击自动关联省份)'; } else if (!isNationalMode && provVal) { headerText = provVal + ' · 下属城市(共 ' + items.length + ' 个,也可直接输入搜索全国城市)'; } else { headerText = '全国全部城市(共 ' + items.length + ' 个,点击自动填充省份,可输入搜索)'; } $('
').text(headerText).appendTo($dropdown); if (!items.length) { $('
').text( '未找到匹配城市,可直接保存自定义城市「' + currentCity + '」' ).appendTo($dropdown); return; } for (var idx = 0; idx < items.length; idx++) { var cObj = items[idx]; var distCount = (tree.districtMap[cObj.province + '|' + cObj.city] || []).length; var $item = $('
') .toggleClass('is-active', cObj.city === currentCity && (!provVal || cObj.province === provVal)) .attr('data-province', cObj.province) .attr('data-city', cObj.city); $('').text(cObj.city).appendTo($item); var subText = isNationalMode ? cObj.province : (distCount ? (distCount + ' 个区县') : ''); if (subText) { $('').text(subText).appendTo($item); } $dropdown.append($item); } scrollActiveIntoView($dropdown); }; /** * 渲染区县下拉列表(支持按当前省市展示、已添加标记,以及全国区县关键字检索反填) * @param {boolean} filterByInput 是否根据当前输入内容过滤 */ var renderDistrictDropdown = function (filterByInput) { var $dropdown = $('#district-dropdown'); var provVal = resolveProvinceKey($province.val()); var cityVal = String($city.val() || '').trim(); var currentDist = String($district.val() || '').trim(); var keyword = filterByInput ? currentDist.toLowerCase() : ''; $dropdown.empty(); // 如果还没选省份但已选城市,尝试从全国城市反查省份 if (!provVal && cityVal) { for (var cIdx = 0; cIdx < tree.allCities.length; cIdx++) { if (tree.allCities[cIdx].city === cityVal) { provVal = tree.allCities[cIdx].province; break; } } } var items = []; var isNationalSearch = false; var key = provVal + '|' + cityVal; var baseDistricts = tree.districtMap[key] || []; if (baseDistricts.length > 0) { for (var i = 0; i < baseDistricts.length; i++) { var dName = baseDistricts[i]; if (!keyword || dName.toLowerCase().indexOf(keyword) !== -1) { items.push({ province: provVal, city: cityVal, district: dName }); } } } // 若在当前城市下未搜到或尚未选择省市,且有搜索词,则跨全国区县搜索 if (keyword && items.length === 0) { isNationalSearch = true; for (var j = 0; j < tree.allDistricts.length; j++) { var dObj = tree.allDistricts[j]; if (dObj.district.toLowerCase().indexOf(keyword) !== -1) { items.push(dObj); if (items.length >= 120) { break; } } } } if (!provVal && !cityVal && !keyword) { $('
').text('区县选择提示').appendTo($dropdown); $('
').text( '请先选择省份或城市,也可直接在此输入区县名称搜索全国区县' ).appendTo($dropdown); return; } var headerText = isNationalSearch ? ('全国区县搜索结果(点击自动填充省/市/区县)') : ((cityVal || '当前城市') + ' · 下属区县(共 ' + items.length + ' 个,支持自定义输入)'); $('
').text(headerText).appendTo($dropdown); if (!items.length) { $('
').text( currentDist ? ('可直接保存自定义区县:「' + currentDist + '」') : '暂无预设区县,请直接输入区县名称' ).appendTo($dropdown); return; } for (var k = 0; k < items.length; k++) { var item = items[k]; var isAdded = !!tree.addedMap[item.province + '|' + item.city + '|' + item.district]; var $item = $('
') .toggleClass('is-active', item.district === currentDist && item.city === cityVal) .attr('data-province', item.province) .attr('data-city', item.city) .attr('data-district', item.district); $('').text(item.district).appendTo($item); if (isNationalSearch) { $('').text(item.province + ' / ' + item.city).appendTo($item); } else if (isAdded) { $('').text('已添加').appendTo($item); } $dropdown.append($item); } scrollActiveIntoView($dropdown); }; /** * 展开指定层级的下拉面板 * @param {string} level province | city | district * @param {boolean} filterByInput 是否按输入关键字过滤 */ var openDropdown = function (level, filterByInput) { var $wrap = $('.fc-area-select-wrap[data-level="' + level + '"]'); closeAllDropdowns($wrap); $wrap.addClass('is-open'); if (level === 'province') { renderProvinceDropdown(!!filterByInput); } else if (level === 'city') { renderCityDropdown(!!filterByInput); } else if (level === 'district') { renderDistrictDropdown(!!filterByInput); } }; // 聚焦或点击输入框时展开完整候选列表(不因已有值而隐藏其他选项) $province.on('focus click', function () { openDropdown('province', false); }); $city.on('focus click', function () { openDropdown('city', false); }); $district.on('focus click', function () { openDropdown('district', false); }); // 输入文字时按关键字实时过滤 $province.on('input', function () { refreshPreview(); openDropdown('province', true); }); $city.on('input', function () { refreshPreview(); openDropdown('city', true); }); $district.on('input', function () { refreshPreview(); openDropdown('district', true); autoResolveCoordinates(); }); // 选择省份项 $('#province-dropdown').on('mousedown', '.fc-area-dropdown__item', function (e) { e.preventDefault(); var selectedProv = String($(this).attr('data-province') || ''); var prevProv = normalizeProvince($province.val()); $province.val(selectedProv).trigger('change').trigger('validate'); if (selectedProv !== prevProv) { $city.val(''); $district.val(''); } var cities = tree.cityMap[selectedProv] || []; if (cities.length === 1) { // 直辖市(如北京市 -> 北京市)自动填充城市并直接展开区县 $city.val(cities[0]).trigger('change').trigger('validate'); refreshPreview(); $district.trigger('focus'); openDropdown('district', false); } else { refreshPreview(); $city.trigger('focus'); openDropdown('city', false); } }); // 选择城市项(支持跨省选城自动反填省份) $('#city-dropdown').on('mousedown', '.fc-area-dropdown__item', function (e) { e.preventDefault(); var selectedProv = String($(this).attr('data-province') || ''); var selectedCity = String($(this).attr('data-city') || ''); var prevCity = String($city.val() || '').trim(); if (selectedProv && String($province.val() || '').trim() !== selectedProv) { $province.val(selectedProv).trigger('change').trigger('validate'); } $city.val(selectedCity).trigger('change').trigger('validate'); if (selectedCity !== prevCity) { $district.val(''); } refreshPreview(); $district.trigger('focus'); openDropdown('district', false); }); // 选择区县项(支持全国搜索区县自动反填省份和城市) $('#district-dropdown').on('mousedown', '.fc-area-dropdown__item', function (e) { e.preventDefault(); var selectedProv = String($(this).attr('data-province') || ''); var selectedCity = String($(this).attr('data-city') || ''); var selectedDist = String($(this).attr('data-district') || ''); if (selectedProv && String($province.val() || '').trim() !== selectedProv) { $province.val(selectedProv).trigger('change').trigger('validate'); } if (selectedCity && String($city.val() || '').trim() !== selectedCity) { $city.val(selectedCity).trigger('change').trigger('validate'); } $district.val(selectedDist).trigger('change').trigger('validate'); closeAllDropdowns(); refreshPreview(); autoResolveCoordinates(); }); // 清空按钮事件(清空当前及下级,并重新展开当前下拉) $('.fc-area-select-clear').on('mousedown', function (e) { e.preventDefault(); e.stopPropagation(); var $wrap = $(this).closest('.fc-area-select-wrap'); var level = $wrap.attr('data-level'); if (level === 'province') { $province.val(''); $city.val(''); $district.val(''); refreshPreview(); $province.trigger('focus'); openDropdown('province', false); } else if (level === 'city') { $city.val(''); $district.val(''); refreshPreview(); $city.trigger('focus'); openDropdown('city', false); } else if (level === 'district') { $district.val(''); refreshPreview(); $district.trigger('focus'); openDropdown('district', false); } }); // 点击组件外部时关闭下拉列表 $(document).on('mousedown.fcAreaDropdown', function (e) { if (!$(e.target).closest('.fc-area-select-wrap').length) { closeAllDropdowns(); } }); // 按 ESC 关闭下拉列表 $(document).on('keydown.fcAreaDropdown', function (e) { if (e.keyCode === 27) { closeAllDropdowns(); } }); // 地图选点完成回调:不仅填充坐标,还可根据地图所选位置自动反填省 / 市 / 区县 $('.fc-area-map-btn').data('callback', function (res) { if (!res) { return; } var fullText = String(res.address || '') + ' ' + ($.isArray(res.rawParts) ? res.rawParts.join(' ') : ''); var matchedProv = resolveProvinceKey(res.province || ''); if (!matchedProv && fullText) { for (var pIdx = 0; pIdx < tree.provinces.length; pIdx++) { var pCandidate = tree.provinces[pIdx]; var pShort = pCandidate.replace(/省|市|自治区|特别行政区|壮族|回族|维吾尔/g, ''); if (fullText.indexOf(pCandidate) !== -1 || (pShort.length >= 2 && fullText.indexOf(pShort) !== -1)) { matchedProv = pCandidate; break; } } } var matchedCity = String(res.city || '').trim(); if (matchedProv && tree.cityMap[matchedProv]) { var cCandidates = tree.cityMap[matchedProv]; if (cCandidates.length === 1) { matchedCity = cCandidates[0]; } else if (!matchedCity || cCandidates.indexOf(matchedCity) === -1) { for (var cIdx = 0; cIdx < cCandidates.length; cIdx++) { var cItem = cCandidates[cIdx]; var cShort = cItem.replace(/市|自治州|地区|盟/g, ''); if (fullText.indexOf(cItem) !== -1 || (cShort.length >= 2 && fullText.indexOf(cShort) !== -1)) { matchedCity = cItem; break; } } } } var matchedDist = String(res.district || '').trim(); if (matchedProv && matchedCity && tree.districtMap[matchedProv + '|' + matchedCity]) { var dCandidates = tree.districtMap[matchedProv + '|' + matchedCity]; if (!matchedDist || dCandidates.indexOf(matchedDist) === -1) { for (var dIdx = 0; dIdx < dCandidates.length; dIdx++) { if (fullText.indexOf(dCandidates[dIdx]) !== -1) { matchedDist = dCandidates[dIdx]; break; } } } } if (matchedProv) { $province.val(matchedProv).trigger('change').trigger('validate'); } if (matchedCity) { $city.val(matchedCity).trigger('change').trigger('validate'); } if (matchedDist) { $district.val(matchedDist).trigger('change').trigger('validate'); } refreshPreview(); }); }); } } }; return Controller; });