import Vue from 'vue' import { getPinyin } from '@/api/base' /** * 提取拼音首字母 * @param {string} text - 中文字符串 * @returns {string} 拼音首字母大写字符串 */ function extractFirstLetters(text) { // 简单的拼音首字母映射表(常用汉字) const pinyinMap = { // 这里可以添加更多常用汉字的映射 } // 基础实现:使用正则提取汉字并获取首字母 // 注意:这只是一个简单的实现,完整的实现需要更全的汉字映射表或使用专业的拼音库 let result = '' const reg = /[\u4e00-\u9fa5]/g const matches = text.match(reg) if (matches) { // 如果有后端接口,则优先使用后端接口 // 否则使用简单的前端实现 matches.forEach((char) => { // 这里使用一个简单的方法来获取拼音首字母 // 实际应用中可以使用更完善的拼音库 const code = char.charCodeAt(0) if (code >= 0x4e00 && code < 0x9fa5) { // 这里是一个简化的实现,实际项目中建议使用完整的拼音库 // 或者使用后端接口获取准确的拼音 result += String.fromCharCode(65 + ((code - 0x4e00) % 26)) } }) } return result.toUpperCase() } // 创建拼音缩写指令 Vue.directive('pinyin-abbreviation', { // 绑定指令时执行 bind(el, binding, vnode) { // 获取目标输入框 let target = el if (el.tagName !== 'INPUT' && el.tagName !== 'TEXTAREA') { target = el.querySelector('input, textarea') } if (!target) return // 获取配置选项 const options = binding.value || {} const targetInput = options.target || null // 目标输入框的v-model字段名 const uppercase = options.uppercase === true // 是否大写,默认为false const useBackend = options.useBackend !== false // 是否使用后端接口,默认为true // 处理输入事件 const handleInput = async (e) => { const chineseText = e.target.value let abbreviation = '' if (useBackend) { try { // 调用后端接口获取拼音 const response = await getPinyin(chineseText) // 修改: 正确处理响应数据,不再假设存在value字段 if (response) { // 如果响应直接是字符串 if (typeof response === 'string') { abbreviation = response } // 如果响应是对象且包含data字段 else if (response.data) { abbreviation = response.data } // 如果响应是对象且包含value字段 else if (response.value) { abbreviation = response.value } } } catch (error) { console.error('获取拼音失败,使用前端备用方案', error) // 失败时使用前端备用方案 abbreviation = extractFirstLetters(chineseText) } } else { // 直接使用前端实现 abbreviation = extractFirstLetters(chineseText) } // 根据配置决定是否大写 if (uppercase) { abbreviation = abbreviation.toUpperCase() } // 如果指定了目标输入框,则将结果设置到目标 if (targetInput && vnode.context) { try { // 处理嵌套属性路径,如 'formData.alias' const pathParts = targetInput.split('.') let currentObj = vnode.context // 遍历路径,直到倒数第二个属性 for (let i = 0; i < pathParts.length - 1; i++) { const part = pathParts[i] // 确保中间对象存在 if (!currentObj[part]) { currentObj[part] = {} } currentObj = currentObj[part] } // 获取最后一个属性名 const lastPart = pathParts[pathParts.length - 1] // 使用 Vue 的 set 方法确保响应式更新 if (vnode.context.$set && currentObj) { vnode.context.$set(currentObj, lastPart, abbreviation) } else if (currentObj) { // 兼容性处理,直接赋值 currentObj[lastPart] = abbreviation } } catch (e) { console.error(`设置目标字段 ${targetInput} 失败:`, e) // 失败时回退到 dataset 存储 el.dataset.pinyinAbbreviation = abbreviation } } else { // 否则可以将结果存储到某个属性中供使用 el.dataset.pinyinAbbreviation = abbreviation } } // 添加事件监听器 target.addEventListener('input', handleInput) // 存储处理函数,以便在解绑时移除 el._pinyinInputHandler = handleInput // 如果元素已经有值,初始化时就处理一次 if (target.value) { handleInput({ target }) } }, // 更新指令时执行 update(el, binding) { // 可以在这里处理指令值变化的逻辑 }, // 解绑指令时执行 unbind(el) { // 获取目标输入框 let target = el if (el.tagName !== 'INPUT' && el.tagName !== 'TEXTAREA') { target = el.querySelector('input, textarea') } // 移除事件监听器 if (target && el._pinyinInputHandler) { target.removeEventListener('input', el._pinyinInputHandler) delete el._pinyinInputHandler } }, }) // 同时导出一个工具函数供组件内使用 export function getPinyinAbbreviation(text, options = {}) { const { useBackend = false, uppercase = false } = options if (useBackend) { // 如果需要异步获取,这里返回一个Promise return new Promise((resolve, reject) => { getPinyin(text) .then((response) => { if (response) { let result = '' // 如果响应直接是字符串 if (typeof response === 'string') { result = response } // 如果响应是对象且包含data字段 else if (response.data) { result = response.data } // 如果响应是对象且包含value字段 else if (response.value) { result = response.value } resolve(uppercase ? result.toUpperCase() : result) } else { resolve('') } }) .catch((error) => { console.error('获取拼音失败', error) // 失败时使用前端备用方案 const fallbackResult = extractFirstLetters(text) resolve(uppercase ? fallbackResult.toUpperCase() : fallbackResult) }) }) } else { // 同步获取 const result = extractFirstLetters(text) return uppercase ? result.toUpperCase() : result } }