You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1695 lines
52 KiB

9 months ago
9 months ago
8 months ago
9 months ago
8 months ago
9 months ago
8 months ago
9 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
8 months ago
9 months ago
8 months ago
8 months ago
9 months ago
8 months ago
8 months ago
8 months ago
9 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
8 months ago
9 months ago
9 months ago
8 months ago
9 months ago
  1. <template>
  2. <div class="property-form">
  3. <!-- 文本属性 -->
  4. <div v-if="element.type === 'text'" class="form-section">
  5. <el-form label-position="top" size="small">
  6. <el-form-item label="数据类型">
  7. <el-select v-model="element.dataType" size="mini" style="width: 100%;" @change="onDataTypeChange">
  8. <el-option label="普通文本" value="text" />
  9. <el-option label="数字" value="number" />
  10. <el-option label="日期" value="date" />
  11. <el-option label="字符串" value="string" />
  12. </el-select>
  13. </el-form-item>
  14. <el-form-item label="文本内容">
  15. <div class="input-with-button">
  16. <el-input v-model="element.data" placeholder="请输入文本" />
  17. <el-button type="primary" size="mini" @click="$emit('data-source', element)">
  18. 数据源
  19. </el-button>
  20. </div>
  21. </el-form-item>
  22. <el-form-item label="不显示规则(如:XXX=N)">
  23. <div class="font-size-row">
  24. <el-input
  25. v-model="element.showElement"
  26. controls-position="right"
  27. size="mini"
  28. class="font-size-input"
  29. />
  30. <el-tooltip content="勾选后内容前面展示☑" placement="top">
  31. <el-checkbox
  32. v-model="element.isChecked"
  33. size="small"
  34. class="inline-checkbox"
  35. >
  36. 打勾
  37. </el-checkbox>
  38. </el-tooltip>
  39. </div>
  40. </el-form-item>
  41. <el-form-item >
  42. <div class="form-row">
  43. <el-form-item label="字体" class="form-item-half">
  44. <el-select
  45. v-model="element.fontFamily"
  46. size="mini"
  47. style="width: 100%;"
  48. placeholder="选择字体"
  49. filterable
  50. :loading="fontLoading"
  51. @focus="loadAvailableFonts"
  52. @change="onFontFamilyChange"
  53. >
  54. <el-option-group
  55. v-for="group in groupedFonts"
  56. :key="group.category"
  57. :label="group.label"
  58. >
  59. <el-option
  60. v-for="font in group.fonts"
  61. :key="font.value"
  62. :label="font.name"
  63. :value="font.value"
  64. :disabled="!font.supported"
  65. >
  66. <span style="float: left">{{ font.name }}</span>
  67. <span style="float: right; color: #8492a6; font-size: 11px">
  68. {{ font.description }}
  69. <i v-if="!font.supported" class="el-icon-warning" style="color: #f56c6c;" title="不支持ZPL打印"></i>
  70. </span>
  71. </el-option>
  72. </el-option-group>
  73. </el-select>
  74. </el-form-item>
  75. <el-form-item label="文本对齐" class="form-item-half">
  76. <el-select v-model="element.textAlign" size="mini" style="width: 100%;" placeholder="对齐方式">
  77. <el-option label="左对齐" value="left" />
  78. <el-option label="居中" value="center" />
  79. <el-option label="右对齐" value="right" />
  80. </el-select>
  81. </el-form-item>
  82. </div>
  83. </el-form-item>
  84. <el-form-item label="字体大小">
  85. <div class="font-size-row">
  86. <el-input
  87. v-model="element.fontSize"
  88. :min="8"
  89. :max="200"
  90. controls-position="right"
  91. size="mini"
  92. class="font-size-input"
  93. />
  94. <el-checkbox v-model="element.bold" size="small" class="inline-checkbox">加粗</el-checkbox>
  95. <el-checkbox v-model="element.newline" size="small" class="inline-checkbox">自动换行</el-checkbox>
  96. </div>
  97. </el-form-item>
  98. <!-- <el-form-item label="字体样式">
  99. <div class="font-style-row">
  100. <el-checkbox v-model="element.fontItalic" size="small" class="inline-checkbox">斜体</el-checkbox>
  101. <el-checkbox v-model="element.fontUnderline" size="small" class="inline-checkbox">下划线</el-checkbox>
  102. <div class="spacing-controls">
  103. <span class="spacing-label">字符间距:</span>
  104. <el-input
  105. v-model="element.letterSpacing"
  106. :min="0"
  107. :max="20"
  108. controls-position="right"
  109. size="mini"
  110. class="spacing-input"
  111. placeholder="0"
  112. />
  113. </div>
  114. </div>
  115. </el-form-item>-->
  116. <template v-if="element.newline">
  117. <div class="form-row">
  118. <el-form-item label="文本宽度(mm)" class="form-item-half">
  119. <el-input
  120. v-model="element.lineWidth"
  121. :min="50"
  122. :max="1000"
  123. controls-position="right"
  124. size="mini"
  125. />
  126. </el-form-item>
  127. <el-form-item label="文本行数" class="form-item-half">
  128. <el-input
  129. v-model="element.lineRows"
  130. :min="1"
  131. :max="10"
  132. controls-position="right"
  133. size="mini"
  134. />
  135. </el-form-item>
  136. </div>
  137. </template>
  138. <template v-if="element.dataType === 'number'">
  139. <el-form-item label="小数位数" >
  140. <div class="font-size-row">
  141. <el-input v-model="element.decimalPlaces" controls-position="right" size="mini"/>
  142. <el-checkbox v-model="element.showDecimalPlaces" size="small" class="inline-checkbox">整数显示小数位</el-checkbox>
  143. <el-checkbox v-model="element.thousandsSeparator" size="small" class="inline-checkbox">千位分隔符</el-checkbox>
  144. <el-checkbox v-model="element.roundHalfUp" size="small" class="inline-checkbox">四舍五入</el-checkbox>
  145. </div>
  146. </el-form-item>
  147. </template>
  148. <!-- 日期类型设置 -->
  149. <template v-if="element.dataType === 'date'">
  150. <div class="form-row">
  151. <el-form-item label="数据源" class="form-item-half">
  152. <el-select
  153. v-model="element.dateSourceType"
  154. size="mini"
  155. style="width: 100%;"
  156. @change="onDateSourceTypeChange"
  157. >
  158. <el-option label="字段值" value="field" />
  159. <el-option label="当前日期" value="current" />
  160. </el-select>
  161. </el-form-item>
  162. <el-form-item label="提取类型" class="form-item-half">
  163. <el-select v-model="element.dateExtractType" size="mini" style="width: 100%;">
  164. <el-option label="完整日期" value="full" />
  165. <el-option label="提取年" value="year" />
  166. <el-option label="提取月" value="month" />
  167. <el-option label="提取日" value="day" />
  168. <el-option label="提取周别" value="week" />
  169. <el-option label="提取周几" value="weekday" />
  170. </el-select>
  171. </el-form-item>
  172. <el-form-item label="加减天数" class="form-item-half">
  173. <el-input
  174. v-model="element.dateOffsetDays"
  175. controls-position="right" size="mini"
  176. style="width: 100%;"/>
  177. </el-form-item>
  178. </div>
  179. <template v-if="element.dateExtractType === 'week'">
  180. <el-form-item label="第一周日期">
  181. <el-date-picker
  182. v-model="element.firstWeekDate"
  183. type="date"
  184. placeholder="选择第一周日期"
  185. size="mini"
  186. style="width: 100%;"
  187. format="yyyy-MM-dd"
  188. value-format="yyyy-MM-dd">
  189. </el-date-picker>
  190. </el-form-item>
  191. </template>
  192. <template v-if="element.dateExtractType === 'weekday'">
  193. <el-form-item label="第一天是周几">
  194. <el-select v-model="element.firstDayOfWeek" size="mini" style="width: 100%;">
  195. <el-option label="周日" value="0" />
  196. <el-option label="周一" value="1" />
  197. <el-option label="周二" value="2" />
  198. <el-option label="周三" value="3" />
  199. <el-option label="周四" value="4" />
  200. <el-option label="周五" value="5" />
  201. <el-option label="周六" value="6" />
  202. </el-select>
  203. </el-form-item>
  204. </template>
  205. <template v-if="element.dateExtractType === 'full'">
  206. <div class="form-row">
  207. <el-form-item label="日期格式" class="form-item-half">
  208. <el-select v-model="element.dateFormat" size="mini" style="width: 100%;">
  209. <el-option label="年月日" value="ymd" />
  210. <el-option label="日月年" value="dmy" />
  211. <el-option label="月日年" value="mdy" />
  212. </el-select>
  213. </el-form-item>
  214. <el-form-item label="分隔符" class="form-item-half">
  215. <el-select v-model="element.dateSeparator" size="mini" style="width: 100%;">
  216. <el-option label="-" value="-" />
  217. <el-option label="/" value="/" />
  218. <el-option label="." value="." />
  219. <el-option label="无" value="" />
  220. </el-select>
  221. </el-form-item>
  222. </div>
  223. <div class="form-row">
  224. <el-form-item label="年份位数" class="form-item-half">
  225. <el-select v-model="element.yearDigits" size="mini" style="width: 100%;">
  226. <el-option label="4位(2024)" value="4" />
  227. <el-option label="2位(24)" value="2" />
  228. </el-select>
  229. </el-form-item>
  230. <el-form-item label="月日位数" class="form-item-half">
  231. <el-select v-model="element.monthDayDigits" size="mini" style="width: 100%;">
  232. <el-option label="2位(01)" value="2" />
  233. <el-option label="1位(1)" value="1" />
  234. </el-select>
  235. </el-form-item>
  236. </div>
  237. </template>
  238. </template>
  239. <!-- 字符串类型设置 -->
  240. <template v-if="element.dataType === 'string'">
  241. <el-form-item label="字符串处理类型">
  242. <el-select v-model="element.stringProcessType" size="mini" style="width: 100%;">
  243. <el-option label="无处理" value="none" />
  244. <el-option label="截取前面字符" value="substring_start" />
  245. <el-option label="截取后面字符" value="substring_end" />
  246. <el-option label="按字符分割" value="split" />
  247. <el-option label="替换字符" value="replace" />
  248. </el-select>
  249. </el-form-item>
  250. <template v-if="element.stringProcessType === 'substring_start'">
  251. <el-form-item label="截取前面位数">
  252. <el-input
  253. v-model="element.substringStartLength"
  254. :min="1"
  255. :max="1000"
  256. controls-position="right"
  257. size="mini"
  258. placeholder="截取前面多少位"
  259. />
  260. </el-form-item>
  261. </template>
  262. <template v-if="element.stringProcessType === 'substring_end'">
  263. <el-form-item label="截取后面位数">
  264. <el-input
  265. v-model="element.substringEndLength"
  266. :min="1"
  267. :max="1000"
  268. controls-position="right"
  269. size="mini"
  270. placeholder="截取后面多少位"
  271. />
  272. </el-form-item>
  273. </template>
  274. <template v-if="element.stringProcessType === 'split'">
  275. <div class="form-row">
  276. <el-form-item label="分割字符" class="form-item-half">
  277. <el-input
  278. v-model="element.splitCharacter"
  279. size="mini"
  280. placeholder="分割字符"
  281. />
  282. </el-form-item>
  283. <el-form-item label="取第几段" class="form-item-half">
  284. <el-input
  285. v-model="element.splitIndex"
  286. :min="0"
  287. :max="100"
  288. controls-position="right"
  289. size="mini"
  290. placeholder="0表示第1段"
  291. />
  292. </el-form-item>
  293. </div>
  294. </template>
  295. <template v-if="element.stringProcessType === 'replace'">
  296. <div class="form-row">
  297. <el-form-item label="查找字符" class="form-item-half">
  298. <el-input
  299. v-model="element.replaceFrom"
  300. size="mini"
  301. placeholder="要替换的字符"
  302. />
  303. </el-form-item>
  304. <el-form-item label="替换为" class="form-item-half">
  305. <el-input
  306. v-model="element.replaceTo"
  307. size="mini"
  308. placeholder="替换成的字符"
  309. />
  310. </el-form-item>
  311. </div>
  312. </template>
  313. </template>
  314. </el-form>
  315. </div>
  316. <!-- 一维码属性 -->
  317. <div v-else-if="element.type === 'onecode'" class="form-section">
  318. <el-form label-position="top" size="small">
  319. <el-form-item label="数据内容">
  320. <div class="input-with-button">
  321. <el-input
  322. v-model="element.data"
  323. placeholder="请输入一维码数据"
  324. type="textarea"
  325. :rows="2"
  326. maxlength="1000"
  327. show-word-limit
  328. />
  329. <el-button type="primary" size="mini" @click="$emit('data-source', element)">
  330. 数据源
  331. </el-button>
  332. <el-button type="success" size="mini" @click="$emit('element-combination', element)">
  333. 元素组合
  334. </el-button>
  335. </div>
  336. </el-form-item>
  337. <el-form-item label="不显示规则(如:XXX=N)" class="form-item-half">
  338. <el-input v-model="element.showElement" controls-position="right" size="mini"/>
  339. </el-form-item>
  340. <div class="form-row">
  341. <el-form-item label="条码类型" class="form-item-half">
  342. <el-select v-model="element.barcodeType" size="mini" style="width: 100%;">
  343. <el-option label="CODE128" value="CODE128" />
  344. <el-option label="CODE39" value="CODE39" />
  345. <el-option label="CODE93" value="CODE93" />
  346. <el-option label="EAN13" value="EAN13" />
  347. <el-option label="EAN8" value="EAN8" />
  348. <el-option label="UPCA" value="UPCA" />
  349. <el-option label="UPCE" value="UPCE" />
  350. </el-select>
  351. </el-form-item>
  352. <el-form-item label="明文显示" class="form-item-half">
  353. <el-radio-group v-model="element.showContent" size="mini">
  354. <el-radio :label="true"></el-radio>
  355. <el-radio :label="false"></el-radio>
  356. </el-radio-group>
  357. </el-form-item>
  358. </div>
  359. <div class="form-row">
  360. <el-form-item label="窄条宽(范围0.085-0.85mm)" class="form-item-half">
  361. <el-input
  362. v-model="element.width"
  363. controls-position="right"
  364. size="mini"
  365. />
  366. </el-form-item>
  367. <el-form-item label="高度(mm)" class="form-item-half">
  368. <el-input
  369. v-model="element.height"
  370. controls-position="right"
  371. size="mini"
  372. />
  373. </el-form-item>
  374. </div>
  375. </el-form>
  376. </div>
  377. <!-- 二维码属性 -->
  378. <div v-else-if="element.type === 'qrcode'" class="form-section">
  379. <el-form label-position="top" size="small">
  380. <el-form-item label="数据内容">
  381. <div class="input-with-button">
  382. <el-input
  383. v-model="element.data"
  384. placeholder="请输入二维码数据"
  385. type="textarea"
  386. :rows="2"
  387. maxlength="1000"
  388. show-word-limit
  389. />
  390. <el-button type="primary" size="mini" @click="$emit('data-source', element)">
  391. 数据源
  392. </el-button>
  393. <el-button type="success" size="mini" @click="$emit('element-combination', element)">
  394. 元素组合
  395. </el-button>
  396. </div>
  397. </el-form-item>
  398. <el-form-item label="不显示规则(如:XXX=N)" class="form-item-half">
  399. <el-input v-model="element.showElement" controls-position="right" size="mini"/>
  400. </el-form-item>
  401. <div class="form-row">
  402. <el-form-item label="尺寸(mm)" class="form-item-half">
  403. <el-input
  404. v-model="element.height"
  405. :min="3"
  406. :max="50"
  407. :step="0.5"
  408. controls-position="right"
  409. size="mini"
  410. @change="validateQRSize"
  411. />
  412. </el-form-item>
  413. <el-form-item label="明文显示" class="form-item-half">
  414. <el-radio-group v-model="element.showContent" size="mini">
  415. <el-radio :label="true"></el-radio>
  416. <el-radio :label="false"></el-radio>
  417. </el-radio-group>
  418. </el-form-item>
  419. </div>
  420. <div class="form-tip">
  421. <div v-if="element.data && element.data.length > 200" class="tip-warning">
  422. 内容较长({{ element.data.length }}字符)建议尺寸15mm系统将自动优化
  423. </div>
  424. <div v-else-if="element.data && element.data.length > 100" class="tip-info">
  425. 内容中等({{ element.data.length }}字符)建议尺寸12mm系统将自动优化
  426. </div>
  427. <div v-else class="tip-normal">
  428. 内容较短({{ element.data ? element.data.length : 0 }}字符)当前尺寸足够
  429. </div>
  430. </div>
  431. </el-form>
  432. </div>
  433. <!-- 图片属性 -->
  434. <div v-else-if="element.type === 'pic'" class="form-section">
  435. <el-form label-position="top" size="small">
  436. <el-form-item label="图片上传">
  437. <div class="image-upload">
  438. <input
  439. ref="fileInput"
  440. type="file"
  441. accept="image/*"
  442. @change="handleImageUpload"
  443. style="display: none;"
  444. />
  445. <el-button type="primary"
  446. icon="el-icon-upload"
  447. @click="handleSelectImage">
  448. 选择图片
  449. </el-button>
  450. </div>
  451. </el-form-item>
  452. <div v-if="element.previewUrl" class="image-preview">
  453. <img :src="element.previewUrl" alt="预览" />
  454. </div>
  455. <!-- 图片尺寸设置 -->
  456. <div class="form-row">
  457. <el-form-item label="宽度(像素)" class="form-item-half">
  458. <el-input
  459. v-model="element.width"
  460. :min="50"
  461. :max="800"
  462. controls-position="right"
  463. size="mini"
  464. @change="onImageSizeChange"
  465. />
  466. </el-form-item>
  467. <el-form-item label="高度(像素)" class="form-item-half">
  468. <el-input
  469. v-model="element.height"
  470. :min="50"
  471. :max="800"
  472. controls-position="right"
  473. size="mini"
  474. @change="onImageSizeChange"
  475. />
  476. </el-form-item>
  477. </div>
  478. <el-form-item label="不显示规则(如:XXX=N)" class="form-item-half">
  479. <el-input v-model="element.showElement" controls-position="right" size="mini"/>
  480. </el-form-item>
  481. </el-form>
  482. </div>
  483. <!-- 线条属性 -->
  484. <div v-else-if="['hLine', 'vLine'].includes(element.type)" class="form-section">
  485. <el-form label-position="top" size="small">
  486. <div class="form-row">
  487. <el-form-item label="宽度" class="form-item-half">
  488. <el-input
  489. v-model="element.width"
  490. :min="1"
  491. :max="1000"
  492. controls-position="right"
  493. size="mini"
  494. />
  495. </el-form-item>
  496. <el-form-item label="高度" class="form-item-half">
  497. <el-input
  498. v-model="element.height"
  499. :min="1"
  500. :max="1000"
  501. controls-position="right"
  502. size="mini"
  503. />
  504. </el-form-item>
  505. </div>
  506. </el-form>
  507. </div>
  508. <!-- 流水号属性 -->
  509. <div v-else-if="element.type === 'serialNumber'" class="form-section">
  510. <el-form label-position="top" size="small">
  511. <div class="form-row">
  512. <el-form-item label="名称" class="form-item-half">
  513. <el-input v-model="element.seqName" controls-position="right" size="mini"/>
  514. </el-form-item>
  515. <el-form-item v-if="parentSerialElements.length>0" label="父标签流水号" class="form-item-half">
  516. <el-select clearable v-model="element.parentSerialLabelNo" size="mini" style="width: 100%;" filterable >
  517. <el-option v-for="item in parentSerialElements" :key="item.label_no" :label="(item.seq_name?item.seq_name:'')+'('+item.data+')'"
  518. :value="item.label_no"></el-option>
  519. </el-select>
  520. </el-form-item>
  521. </div>
  522. <div class="form-row" v-if="!element.parentSerialLabelNo">
  523. <el-form-item label="位数" class="form-item-half">
  524. <el-input
  525. v-model="element.digits"
  526. :min="1"
  527. :max="10"
  528. controls-position="right"
  529. size="mini"
  530. placeholder="6"
  531. />
  532. </el-form-item>
  533. <el-form-item label="步长" class="form-item-half">
  534. <el-input
  535. v-model="element.step"
  536. :min="1"
  537. :max="100"
  538. controls-position="right"
  539. size="mini"
  540. placeholder="1"
  541. />
  542. </el-form-item>
  543. </div>
  544. <div class="form-row" v-if="!element.parentSerialLabelNo">
  545. <el-form-item label="字体大小" class="form-item-half">
  546. <el-input
  547. v-model="element.fontSize"
  548. :min="8"
  549. :max="200"
  550. controls-position="right"
  551. size="mini"
  552. placeholder="30"
  553. />
  554. </el-form-item>
  555. <el-form-item label="加粗" class="form-item-half">
  556. <el-checkbox v-model="element.bold" size="middle"></el-checkbox>
  557. </el-form-item>
  558. </div>
  559. <div class="form-row" v-if="!element.parentSerialLabelNo">
  560. <el-form-item label="流水号规则" class="form-item-half">
  561. <el-input v-model="element.data" placeholder="请输入流水号规则" />
  562. <el-button type="primary" size="mini" @click="$emit('data-source', element)">
  563. 数据源
  564. </el-button>
  565. </el-form-item>
  566. </div>
  567. <div class="form-row">
  568. <el-form-item label="流水号信息" class="form-item-half">
  569. <el-button type="primary" size="mini" @click="serialInfoModal(element)">
  570. 查看
  571. </el-button>
  572. </el-form-item>
  573. <el-form-item label="是否显示" class="form-item-half">
  574. <el-checkbox v-model="element.showSerialNumber" size="middle">显示流水号</el-checkbox>
  575. </el-form-item>
  576. </div>
  577. </el-form>
  578. </div>
  579. <!-- 标签内容流水号信息 -->
  580. <comShowLabelSerialInfo ref="comShowLabelSerialInfo" v-drag></comShowLabelSerialInfo>
  581. </div>
  582. </template>
  583. <script>
  584. import comShowLabelSerialInfo from "../com_show_label_serial_info";
  585. import { availableFont,getParentLabelInfo ,getParentSerialElements} from '@/api/labelSetting/label_setting.js'
  586. export default {
  587. name: 'PropertyForm',
  588. props: {
  589. element: {
  590. type: Object,
  591. required: true
  592. }
  593. },
  594. emits: ['data-source', 'image-upload', 'element-combination'],
  595. data() {
  596. return {
  597. availableFonts: [],
  598. fontLoading: false,
  599. fontsLoaded: false,
  600. parentSerialElements: [] // 父标签的流水号元素列表
  601. }
  602. },
  603. computed: {
  604. groupedFonts() {
  605. if (!this.availableFonts.length) {
  606. return []
  607. }
  608. const groups = {}
  609. this.availableFonts.forEach(font => {
  610. const category = font.category || 'other'
  611. if (!groups[category]) {
  612. groups[category] = {
  613. category: category,
  614. label: this.getCategoryLabel(category),
  615. fonts: []
  616. }
  617. }
  618. groups[category].fonts.push(font)
  619. })
  620. // 排序分组
  621. const sortedGroups = Object.values(groups).sort((a, b) => {
  622. const order = ['system', 'chinese', 'english', 'monospace', 'decorative', 'other']
  623. return order.indexOf(a.category) - order.indexOf(b.category)
  624. })
  625. return sortedGroups
  626. }
  627. },
  628. /*组件*/
  629. components: {
  630. comShowLabelSerialInfo,/*标签内容流水号信息的組件*/
  631. },
  632. mounted() {
  633. // 初始化数据类型及相关设置
  634. this.initializeTypeSettings()
  635. // 初始化字体设置
  636. this.initializeFontSettings()
  637. if (this.element.type === 'serialNumber') {
  638. this.getParentLabelInfo()
  639. }
  640. },
  641. watch: {
  642. // 监听元素变化,确保文件输入框状态正确
  643. 'element.id'() {
  644. // 当切换到不同元素时,重置文件输入框
  645. this.$nextTick(() => {
  646. if (this.$refs.fileInput) {
  647. this.$refs.fileInput.value = ''
  648. }
  649. })
  650. },
  651. 'element'() {
  652. // 当切换到不同元素时,获取父流水号
  653. this.$nextTick(() => {
  654. this.initializeTypeSettings()
  655. if (this.element.type === 'serialNumber') {
  656. this.getParentLabelInfo()
  657. }
  658. })
  659. }
  660. },
  661. methods: {
  662. setElementDefault(key, defaultValue) {
  663. const value = this.element[key]
  664. if (value === undefined || value === null || value === '') {
  665. this.$set(this.element, key, defaultValue)
  666. }
  667. },
  668. initializeTypeSettings() {
  669. if (this.element.type !== 'text') {
  670. return
  671. }
  672. this.setElementDefault('dataType', 'text')
  673. if (this.element.dataType === 'date') {
  674. this.setElementDefault('dateSourceType', this.inferDateSourceType(this.element.data))
  675. this.setElementDefault('dateExtractType', 'full')
  676. this.setElementDefault('dateFormat', 'ymd')
  677. this.setElementDefault('dateSeparator', '-')
  678. this.setElementDefault('yearDigits', '4')
  679. this.setElementDefault('monthDayDigits', '2')
  680. this.setElementDefault('firstWeekDate', '')
  681. this.setElementDefault('firstDayOfWeek', '1')
  682. this.setElementDefault('dateOffsetDays', 0)
  683. } else if (this.element.dataType === 'number') {
  684. this.setElementDefault('roundHalfUp', true)
  685. } else if (this.element.dataType === 'string') {
  686. this.setElementDefault('stringProcessType', 'none')
  687. this.setElementDefault('substringStartLength', '')
  688. this.setElementDefault('substringEndLength', '')
  689. this.setElementDefault('splitCharacter', '')
  690. this.setElementDefault('splitIndex', '0')
  691. this.setElementDefault('replaceFrom', '')
  692. this.setElementDefault('replaceTo', '')
  693. }
  694. },
  695. // 获取父标签信息
  696. async getParentLabelInfo() {
  697. if (!this.element.reportId) return null
  698. try {
  699. // 使用API服务获取父标签信息
  700. const response = await getParentLabelInfo({ labelNo: this.element.reportId })
  701. if (response && response.data.code === 200) {
  702. const parentInfo = response.data.data
  703. if (parentInfo && parentInfo.parentLabelNo) {
  704. const response2 = await getParentSerialElements({ labelNo: parentInfo.parentLabelNo })
  705. if (response2.data && response2.data.code === 200) {
  706. this.parentSerialElements = response2.data.data || []
  707. } else {
  708. // 如果API调用失败,使用默认数据
  709. this.parentSerialElements = []
  710. }
  711. }
  712. } else {
  713. // 如果API调用失败,使用默认数据
  714. this.parentSerialElements = []
  715. }
  716. } catch (error) {
  717. console.error('获取父标签信息失败:', error)
  718. this.parentSerialElements = []
  719. }
  720. },
  721. onDataTypeChange(newType) {
  722. // 重置相关设置
  723. if (newType === 'date') {
  724. this.$set(this.element, 'dateSourceType', this.inferDateSourceType(this.element.data))
  725. this.$set(this.element, 'dateExtractType', 'full')
  726. this.$set(this.element, 'dateFormat', 'ymd')
  727. this.$set(this.element, 'dateSeparator', '-')
  728. this.$set(this.element, 'yearDigits', '4')
  729. this.$set(this.element, 'monthDayDigits', '2')
  730. this.$set(this.element, 'firstWeekDate', '')
  731. this.$set(this.element, 'firstDayOfWeek', '1')
  732. this.$set(this.element, 'dateOffsetDays', 0)
  733. } else if (newType === 'number') {
  734. this.$set(this.element, 'roundHalfUp', true)
  735. } else if (newType === 'string') {
  736. this.$set(this.element, 'stringProcessType', 'none')
  737. this.$set(this.element, 'substringStartLength', '')
  738. this.$set(this.element, 'substringEndLength', '')
  739. this.$set(this.element, 'splitCharacter', '')
  740. this.$set(this.element, 'splitIndex', '0')
  741. this.$set(this.element, 'replaceFrom', '')
  742. this.$set(this.element, 'replaceTo', '')
  743. }
  744. },
  745. inferDateSourceType(dataValue) {
  746. return dataValue === '#{CURRENT_DATE_YYYY-MM-DD}' ? 'current' : 'field'
  747. },
  748. onDateSourceTypeChange(sourceType) {
  749. if (sourceType === 'current') {
  750. if (this.element.data && this.element.data !== '#{CURRENT_DATE_YYYY-MM-DD}') {
  751. this.$set(this.element, 'dateFieldDataBackup', this.element.data)
  752. }
  753. this.$set(this.element, 'data', '#{CURRENT_DATE_YYYY-MM-DD}')
  754. } else if (this.element.data === '#{CURRENT_DATE_YYYY-MM-DD}') {
  755. const backupData = this.element.dateFieldDataBackup || ''
  756. this.$set(this.element, 'data', backupData)
  757. }
  758. },
  759. handleSelectImage() {
  760. // 确保文件输入框被重置,然后触发点击
  761. if (this.$refs.fileInput) {
  762. this.$refs.fileInput.value = ''
  763. this.$refs.fileInput.click()
  764. }
  765. },
  766. /*流水号信息的modal*/
  767. serialInfoModal(row){
  768. let rowData = {
  769. labelNo: row.reportId,
  770. itemNo: row.itemNo,
  771. };
  772. //打开组件 去做复制其他标签业务
  773. this.$nextTick(() => {
  774. this.$refs.comShowLabelSerialInfo.init(rowData);
  775. })
  776. },
  777. validateQRSize() {
  778. const dataLength = this.element.data ? this.element.data.length : 0
  779. // 毫米单位限制
  780. if (this.element.height > 50) {
  781. this.$message.warning('二维码最大尺寸为50mm')
  782. this.element.height = 50
  783. } else if (this.element.height < 3) {
  784. this.element.height = 3
  785. }
  786. // 根据数据长度给出尺寸建议
  787. if (dataLength > 200 && this.element.height < 15) {
  788. this.$message.warning('长内容建议使用15mm或以上尺寸,以确保扫描成功')
  789. } else if (dataLength > 100 && this.element.height < 12) {
  790. this.$message.warning('中等长度内容建议使用12mm或以上尺寸')
  791. }
  792. },
  793. /**
  794. * 图片尺寸变化处理
  795. */
  796. onImageSizeChange() {
  797. // 限制图片尺寸范围
  798. if (this.element.width > 800) {
  799. this.$message.warning('图片宽度最大为800像素')
  800. this.element.width = 800
  801. } else if (this.element.width < 50) {
  802. this.element.width = 50
  803. }
  804. if (this.element.height > 800) {
  805. this.$message.warning('图片高度最大为800像素')
  806. this.element.height = 800
  807. } else if (this.element.height < 50) {
  808. this.element.height = 50
  809. }
  810. // 如果已经有图片数据,重新生成ZPL数据
  811. if (this.element.previewUrl) {
  812. this.regenerateImageZPL()
  813. }
  814. },
  815. /**
  816. * 重新生成图片的ZPL数据
  817. */
  818. regenerateImageZPL() {
  819. if (!this.element.previewUrl) return
  820. const img = new Image()
  821. img.onload = () => {
  822. try {
  823. const { zplData } = this.convertImageToZPL(img)
  824. this.element.zplData = zplData
  825. // 触发父组件更新
  826. this.$emit('image-upload', { zplData, previewUrl: this.element.previewUrl })
  827. } catch (error) {
  828. console.error('重新生成图片ZPL失败:', error)
  829. }
  830. }
  831. img.src = this.element.previewUrl
  832. },
  833. async handleImageUpload(event) {
  834. const file = event.target.files[0]
  835. if (!file) return
  836. try {
  837. const imageData = await this.processImage(file)
  838. this.$emit('image-upload', imageData)
  839. // 重置文件输入框的值,确保下次选择相同文件时也能触发change事件
  840. event.target.value = ''
  841. } catch (error) {
  842. this.$message.error('图片处理失败')
  843. // 即使出错也要重置文件输入框
  844. event.target.value = ''
  845. }
  846. },
  847. processImage(file) {
  848. return new Promise((resolve, reject) => {
  849. const reader = new FileReader()
  850. reader.onload = (e) => {
  851. const img = new Image()
  852. img.onload = () => {
  853. try {
  854. const { zplData, previewUrl } = this.convertImageToZPL(img)
  855. resolve({ zplData, previewUrl })
  856. } catch (error) {
  857. reject(error)
  858. }
  859. }
  860. img.onerror = reject
  861. img.src = e.target.result
  862. }
  863. reader.onerror = reject
  864. reader.readAsDataURL(file)
  865. })
  866. },
  867. convertImageToZPL(img) {
  868. // 使用元素的宽度和高度设置,如果没有设置则使用默认值
  869. const targetWidth = parseInt(this.element.width) || 200
  870. const targetHeight = parseInt(this.element.height) || Math.round(img.height * (targetWidth / img.width))
  871. const canvas = document.createElement('canvas')
  872. canvas.width = targetWidth
  873. canvas.height = targetHeight
  874. const ctx = canvas.getContext('2d')
  875. ctx.fillStyle = '#fff'
  876. ctx.fillRect(0, 0, canvas.width, canvas.height)
  877. ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
  878. // 转换为ZPL格式
  879. const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
  880. const { width, height, data } = imageData
  881. const bytesPerRow = Math.ceil(width / 8)
  882. const totalBytes = bytesPerRow * height
  883. let binaryData = ''
  884. for (let y = 0; y < height; y++) {
  885. for (let byteIdx = 0; byteIdx < bytesPerRow; byteIdx++) {
  886. let byteStr = ''
  887. for (let bit = 0; bit < 8; bit++) {
  888. const x = byteIdx * 8 + bit
  889. if (x >= width) {
  890. byteStr += '0'
  891. } else {
  892. const i = (y * width + x) * 4
  893. const r = data[i], g = data[i + 1], b = data[i + 2]
  894. const grayscale = (r + g + b) / 3
  895. byteStr += grayscale < 128 ? '1' : '0'
  896. }
  897. }
  898. const hex = parseInt(byteStr, 2).toString(16).padStart(2, '0').toUpperCase()
  899. binaryData += hex
  900. }
  901. }
  902. return {
  903. zplData: `${totalBytes},${totalBytes},${bytesPerRow},${binaryData}`,
  904. previewUrl: canvas.toDataURL()
  905. }
  906. },
  907. getSerialNumberPreview() {
  908. if (this.element.type !== 'serialNumber') return ''
  909. const prefix = this.element.prefix || ''
  910. const startValue = parseInt(this.element.startValue) || 1
  911. const digits = parseInt(this.element.digits) || 6
  912. const paddedNumber = startValue.toString().padStart(digits, '0')
  913. return `${prefix}${paddedNumber}`
  914. },
  915. // 初始化字体设置
  916. initializeFontSettings() {
  917. if (this.element.type === 'text') {
  918. // 设置默认字体属性
  919. if (!this.element.fontFamily) {
  920. this.$set(this.element, 'fontFamily', 'default')
  921. }
  922. if (!this.element.textAlign) {
  923. this.$set(this.element, 'textAlign', 'left')
  924. }
  925. if (this.element.letterSpacing === undefined) {
  926. this.$set(this.element, 'letterSpacing', 0)
  927. }
  928. if (this.element.fontItalic === undefined) {
  929. this.$set(this.element, 'fontItalic', false)
  930. }
  931. if (this.element.fontUnderline === undefined) {
  932. this.$set(this.element, 'fontUnderline', false)
  933. }
  934. }
  935. },
  936. // 获取字体预览样式
  937. getFontPreviewStyle() {
  938. if (this.element.type !== 'text') return {}
  939. const style = {}
  940. // 字体族
  941. if (this.element.fontFamily && this.element.fontFamily !== 'default') {
  942. style.fontFamily = this.element.fontFamily
  943. }
  944. // 字体大小
  945. if (this.element.fontSize) {
  946. style.fontSize = this.element.fontSize + 'px'
  947. }
  948. // 加粗
  949. if (this.element.bold) {
  950. style.fontWeight = 'bold'
  951. }
  952. // 斜体
  953. if (this.element.fontItalic) {
  954. style.fontStyle = 'italic'
  955. }
  956. // 下划线
  957. if (this.element.fontUnderline) {
  958. style.textDecoration = 'underline'
  959. }
  960. // 文本对齐
  961. if (this.element.textAlign) {
  962. style.textAlign = this.element.textAlign
  963. }
  964. // 字符间距
  965. if (this.element.letterSpacing) {
  966. style.letterSpacing = this.element.letterSpacing + 'px'
  967. }
  968. return style
  969. },
  970. // 加载可用字体
  971. async loadAvailableFonts() {
  972. if (this.fontsLoaded || this.fontLoading) {
  973. return
  974. }
  975. this.fontLoading = true
  976. try {
  977. const response = await availableFont({})
  978. if (response.data.success) {
  979. this.availableFonts = response.data.data || []
  980. this.fontsLoaded = true
  981. console.log('加载字体列表成功,共', this.availableFonts.length, '个字体')
  982. } else {
  983. console.error('加载字体列表失败:', response.data.message)
  984. this.$message.warning('加载字体列表失败,使用默认字体')
  985. this.availableFonts = this.getDefaultFonts()
  986. }
  987. } catch (error) {
  988. console.error('加载字体列表异常:', error)
  989. this.$message.error('加载字体列表异常')
  990. this.availableFonts = this.getDefaultFonts()
  991. } finally {
  992. this.fontLoading = false
  993. }
  994. },
  995. // 获取分类标签
  996. getCategoryLabel(category) {
  997. const labels = {
  998. 'system': '系统字体',
  999. 'chinese': '中文字体',
  1000. 'english': '英文字体',
  1001. 'monospace': '等宽字体',
  1002. 'decorative': '装饰字体',
  1003. 'other': '其他字体'
  1004. }
  1005. return labels[category] || '其他字体'
  1006. },
  1007. // 获取默认字体列表(备用方案)
  1008. getDefaultFonts() {
  1009. return [
  1010. { name: '默认字体', value: 'default', category: 'system', description: '系统默认', supported: true },
  1011. { name: '微软雅黑', value: 'Microsoft YaHei', category: 'chinese', description: '中文字体', supported: true },
  1012. { name: '宋体', value: 'SimSun', category: 'chinese', description: '中文字体', supported: true },
  1013. { name: '黑体', value: 'SimHei', category: 'chinese', description: '中文字体', supported: true },
  1014. { name: 'Arial', value: 'Arial', category: 'english', description: '英文字体', supported: true },
  1015. { name: 'Times New Roman', value: 'Times New Roman', category: 'english', description: '英文字体', supported: true },
  1016. { name: 'Courier New', value: 'Courier New', category: 'monospace', description: '等宽字体', supported: true }
  1017. ]
  1018. },
  1019. // 字体族变化处理
  1020. onFontFamilyChange(value) {
  1021. console.log('字体族变化:', value)
  1022. console.log('当前元素:', this.element)
  1023. // 确保字体值正确设置
  1024. this.$set(this.element, 'fontFamily', value)
  1025. // 触发父组件更新
  1026. this.$emit('font-changed', {
  1027. elementId: this.element.id,
  1028. fontFamily: value
  1029. })
  1030. console.log('字体设置完成,当前字体族:', this.element.fontFamily)
  1031. },
  1032. }
  1033. }
  1034. </script>
  1035. <style scoped>
  1036. .property-form {
  1037. overflow-y: auto;
  1038. }
  1039. .property-form::-webkit-scrollbar {
  1040. width: 4px;
  1041. }
  1042. .property-form::-webkit-scrollbar-track {
  1043. background: #f1f1f1;
  1044. border-radius: 2px;
  1045. }
  1046. .property-form::-webkit-scrollbar-thumb {
  1047. //background: #409eff;
  1048. border-radius: 2px;
  1049. }
  1050. .form-section {
  1051. padding: 10px;
  1052. background: #fafafa;
  1053. border-radius: 4px;
  1054. border: 1px solid #e8e8e8;
  1055. }
  1056. .input-with-button {
  1057. display: flex;
  1058. gap: 6px;
  1059. align-items: flex-start;
  1060. }
  1061. .input-with-button .el-input {
  1062. flex: 1;
  1063. }
  1064. .input-with-button .el-button {
  1065. font-size: 11px;
  1066. padding: 5px 8px;
  1067. height: 28px;
  1068. }
  1069. .form-tip {
  1070. font-size: 11px;
  1071. color: #909399;
  1072. margin-top: 3px;
  1073. padding: 3px 6px;
  1074. background: #f8f9fa;
  1075. border-radius: 3px;
  1076. }
  1077. .form-tip .tip-warning {
  1078. color: #f56c6c;
  1079. font-weight: 500;
  1080. border-left: 2px solid #f56c6c;
  1081. padding-left: 6px;
  1082. }
  1083. .form-tip .tip-info {
  1084. color: #e6a23c;
  1085. font-weight: 500;
  1086. border-left: 2px solid #e6a23c;
  1087. padding-left: 6px;
  1088. }
  1089. .form-tip .tip-normal {
  1090. color: #67c23a;
  1091. font-weight: 500;
  1092. border-left: 2px solid #67c23a;
  1093. padding-left: 6px;
  1094. }
  1095. .image-upload {
  1096. margin-bottom: 8px;
  1097. }
  1098. .image-upload .el-button {
  1099. width: 100%;
  1100. height: 30px;
  1101. border: 1px dashed #d9d9d9;
  1102. border-radius: 4px;
  1103. background: #fafafa;
  1104. font-size: 12px;
  1105. color: black;
  1106. }
  1107. .image-upload .el-button:hover {
  1108. border-color: #409eff;
  1109. background: #f0f9ff;
  1110. }
  1111. .image-preview {
  1112. text-align: center;
  1113. padding: 8px;
  1114. background: #f8f9fa;
  1115. border-radius: 4px;
  1116. border: 1px solid #e8e8e8;
  1117. }
  1118. .image-preview img {
  1119. max-width: 80px;
  1120. max-height: 80px;
  1121. border-radius: 4px;
  1122. border: 1px solid #ddd;
  1123. }
  1124. /* Element UI 表单项紧凑化 */
  1125. .el-form-item {
  1126. margin-bottom: 2px;
  1127. }
  1128. .el-form-item:last-child {
  1129. margin-bottom: 0;
  1130. }
  1131. .el-form-item__label {
  1132. font-size: 12px !important;
  1133. padding-bottom: 6px !important;
  1134. line-height: 1.2 !important;
  1135. color: #606266 !important;
  1136. font-weight: 500 !important;
  1137. }
  1138. .el-input__inner {
  1139. height: 32px !important;
  1140. font-size: 13px !important;
  1141. border-radius: 6px !important;
  1142. border: 1px solid #dcdfe6 !important;
  1143. padding: 0 12px !important;
  1144. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
  1145. }
  1146. .el-input__inner:hover {
  1147. border-color: #c0c4cc !important;
  1148. }
  1149. .el-input__inner:focus {
  1150. border-color: #409eff !important;
  1151. outline: none !important;
  1152. box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;
  1153. }
  1154. .el-input {
  1155. width: 100% !important;
  1156. }
  1157. .el-input .el-input__inner {
  1158. text-align: left !important;
  1159. height: 32px !important;
  1160. padding: 0 35px 0 12px !important;
  1161. }
  1162. .el-checkbox {
  1163. font-size: 12px !important;
  1164. height: 20px !important;
  1165. line-height: 20px !important;
  1166. }
  1167. .el-checkbox__label {
  1168. font-size: 12px !important;
  1169. padding-left: 6px !important;
  1170. }
  1171. .el-checkbox__inner {
  1172. width: 12px !important;
  1173. height: 12px !important;
  1174. }
  1175. .el-checkbox__inner::after {
  1176. height: 5px !important;
  1177. left: 3px !important;
  1178. top: 1px !important;
  1179. width: 2px !important;
  1180. }
  1181. /* 行布局样式 */
  1182. .form-row {
  1183. display: flex;
  1184. gap: 2px;
  1185. align-items: flex-start;
  1186. margin-bottom: 2px;
  1187. }
  1188. .form-row:last-child {
  1189. margin-bottom: 0;
  1190. }
  1191. .form-item-half {
  1192. flex: 1;
  1193. margin-bottom: 0 !important;
  1194. }
  1195. .form-item-half .el-form-item__label {
  1196. margin-bottom: 2px !important;
  1197. }
  1198. /* 数字输入框统一样式 */
  1199. .form-item-half .el-input {
  1200. width: 100% !important;
  1201. }
  1202. .form-item-half .el-input .el-input__inner {
  1203. height: 32px !important;
  1204. font-size: 13px !important;
  1205. padding: 0 35px 0 12px !important;
  1206. border: 1px solid #dcdfe6 !important;
  1207. border-radius: 6px !important;
  1208. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
  1209. }
  1210. .form-item-half .el-input .el-input__inner:hover {
  1211. border-color: #c0c4cc !important;
  1212. }
  1213. .form-item-half .el-input .el-input__inner:focus {
  1214. border-color: #409eff !important;
  1215. outline: none !important;
  1216. box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;
  1217. }
  1218. .form-item-half .el-input .el-input__increase,
  1219. .form-item-half .el-input .el-input__decrease {
  1220. position: absolute !important;
  1221. right: 1px !important;
  1222. width: 32px !important;
  1223. height: 15px !important;
  1224. line-height: 15px !important;
  1225. background: #f5f7fa !important;
  1226. color: #606266 !important;
  1227. cursor: pointer !important;
  1228. font-size: 12px !important;
  1229. border: none !important;
  1230. border-radius: 0 !important;
  1231. transition: all 0.2s !important;
  1232. }
  1233. .form-item-half .el-input .el-input__increase {
  1234. top: 1px !important;
  1235. border-radius: 0 5px 0 0 !important;
  1236. }
  1237. .form-item-half .el-input .el-input__decrease {
  1238. bottom: 1px !important;
  1239. border-radius: 0 0 5px 0 !important;
  1240. }
  1241. .form-item-half .el-input .el-input__increase:hover,
  1242. .form-item-half .el-input .el-input__decrease:hover {
  1243. background: #e6a23c !important;
  1244. color: #fff !important;
  1245. }
  1246. .form-item-half .el-input .el-input__increase:active,
  1247. .form-item-half .el-input .el-input__decrease:active {
  1248. background: #cf9236 !important;
  1249. }
  1250. /* 复选框在行中的样式 */
  1251. .form-item-half .el-checkbox {
  1252. display: block !important;
  1253. margin-bottom: 1px !important;
  1254. margin-right: 0 !important;
  1255. padding-top: 5px;
  1256. padding-left: 1px;
  1257. }
  1258. .form-item-half .el-checkbox:last-child {
  1259. margin-bottom: 0 !important;
  1260. }
  1261. /* 单选按钮组样式 */
  1262. .form-item-half .el-radio-group {
  1263. display: flex !important;
  1264. gap: 8px !important;
  1265. align-items: center !important;
  1266. padding-top: 4px;
  1267. }
  1268. .form-item-half .el-radio {
  1269. margin-right: 0 !important;
  1270. font-size: 12px !important;
  1271. height: 20px !important;
  1272. line-height: 20px !important;
  1273. }
  1274. .form-item-half .el-radio__label {
  1275. font-size: 12px !important;
  1276. padding-left: 4px !important;
  1277. }
  1278. /* 字体样式行布局 */
  1279. .font-style-row {
  1280. display: flex;
  1281. align-items: center;
  1282. gap: 12px;
  1283. flex-wrap: wrap;
  1284. }
  1285. .font-style-row .inline-checkbox {
  1286. margin-right: 0 !important;
  1287. }
  1288. .spacing-controls {
  1289. display: flex;
  1290. align-items: center;
  1291. gap: 6px;
  1292. }
  1293. .spacing-label {
  1294. font-size: 12px;
  1295. color: #606266;
  1296. white-space: nowrap;
  1297. }
  1298. .spacing-input {
  1299. width: 80px !important;
  1300. }
  1301. .spacing-input .el-input__inner {
  1302. height: 28px !important;
  1303. font-size: 12px !important;
  1304. padding: 0 30px 0 8px !important;
  1305. }
  1306. /* 字体预览样式 */
  1307. .font-preview {
  1308. background: #f8f9fa;
  1309. border: 1px solid #e4e7ed;
  1310. border-radius: 4px;
  1311. padding: 8px;
  1312. margin-top: 8px;
  1313. text-align: center;
  1314. min-height: 40px;
  1315. display: flex;
  1316. align-items: center;
  1317. justify-content: center;
  1318. }
  1319. .font-preview-text {
  1320. font-size: 16px;
  1321. color: #333;
  1322. transition: all 0.3s ease;
  1323. }
  1324. .font-debug-info {
  1325. margin-top: 4px;
  1326. text-align: center;
  1327. font-size: 11px;
  1328. line-height: 1.2;
  1329. opacity: 0.8;
  1330. }
  1331. .form-item-half .el-radio__inner {
  1332. width: 12px !important;
  1333. height: 12px !important;
  1334. }
  1335. /* 下拉选择框样式 */
  1336. .form-item-half .el-select {
  1337. width: 100% !important;
  1338. }
  1339. .form-item-half .el-select .el-input__inner {
  1340. height: 32px !important;
  1341. font-size: 13px !important;
  1342. border: 1px solid #dcdfe6 !important;
  1343. border-radius: 6px !important;
  1344. padding: 0 30px 0 12px !important;
  1345. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
  1346. }
  1347. .form-item-half .el-select .el-input__inner:hover {
  1348. border-color: #c0c4cc !important;
  1349. }
  1350. .form-item-half .el-select .el-input__inner:focus {
  1351. border-color: #409eff !important;
  1352. outline: none !important;
  1353. box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;
  1354. }
  1355. /* 复选框组样式 */
  1356. .checkbox-group {
  1357. position: relative;
  1358. display: flex;
  1359. flex-direction: column;
  1360. justify-content: flex-start;
  1361. align-items: flex-start;
  1362. }
  1363. .checkbox-label {
  1364. font-size: 12px !important;
  1365. color: #606266;
  1366. margin-bottom: 4px !important;
  1367. font-weight: 500;
  1368. line-height: 1.2 !important;
  1369. height: 14px;
  1370. padding-bottom: 4px !important;
  1371. display: block;
  1372. }
  1373. .checkbox-group .el-checkbox {
  1374. margin-bottom: 2px !important;
  1375. align-self: flex-start;
  1376. height: 16px !important;
  1377. line-height: 16px !important;
  1378. display: flex !important;
  1379. align-items: center !important;
  1380. }
  1381. .checkbox-group .el-checkbox:last-child {
  1382. margin-bottom: 0 !important;
  1383. }
  1384. .checkbox-group .el-checkbox .el-checkbox__input {
  1385. line-height: 1 !important;
  1386. }
  1387. .checkbox-group .el-checkbox .el-checkbox__label {
  1388. line-height: 1 !important;
  1389. padding-left: 4px !important;
  1390. }
  1391. /* 字体大小行布局 */
  1392. .font-size-row {
  1393. display: flex;
  1394. align-items: center;
  1395. gap: 12px;
  1396. }
  1397. .font-size-input {
  1398. width: 120px !important;
  1399. flex-shrink: 0;
  1400. }
  1401. .font-size-input .el-input__inner {
  1402. height: 32px !important;
  1403. font-size: 13px !important;
  1404. border: 1px solid #dcdfe6 !important;
  1405. border-radius: 6px !important;
  1406. padding: 0 35px 0 12px !important;
  1407. background-color: #fff !important;
  1408. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
  1409. }
  1410. .font-size-input .el-input__inner:hover {
  1411. border-color: #c0c4cc !important;
  1412. }
  1413. .font-size-input .el-input__inner:focus {
  1414. border-color: #409eff !important;
  1415. outline: none !important;
  1416. box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;
  1417. }
  1418. .font-size-input .el-input__increase,
  1419. .font-size-input .el-input__decrease {
  1420. position: absolute !important;
  1421. right: 1px !important;
  1422. width: 32px !important;
  1423. height: 15px !important;
  1424. line-height: 15px !important;
  1425. background: #f5f7fa !important;
  1426. color: #606266 !important;
  1427. cursor: pointer !important;
  1428. font-size: 12px !important;
  1429. border: none !important;
  1430. border-radius: 0 !important;
  1431. transition: all 0.2s !important;
  1432. }
  1433. .font-size-input .el-input__increase {
  1434. top: 1px !important;
  1435. border-radius: 0 5px 0 0 !important;
  1436. }
  1437. .font-size-input .el-input__decrease {
  1438. bottom: 1px !important;
  1439. border-radius: 0 0 5px 0 !important;
  1440. }
  1441. .font-size-input .el-input__increase:hover,
  1442. .font-size-input .el-input__decrease:hover {
  1443. background: #e6a23c !important;
  1444. color: #fff !important;
  1445. }
  1446. .font-size-input .el-input__increase:active,
  1447. .font-size-input .el-input__decrease:active {
  1448. background: #cf9236 !important;
  1449. }
  1450. .inline-checkbox {
  1451. margin: 0 !important;
  1452. height: 28px !important;
  1453. line-height: 28px !important;
  1454. display: flex !important;
  1455. align-items: center !important;
  1456. }
  1457. .inline-checkbox .el-checkbox__label {
  1458. font-size: 12px !important;
  1459. padding-left: 6px !important;
  1460. line-height: 1 !important;
  1461. }
  1462. .inline-checkbox .el-checkbox__input {
  1463. line-height: 1 !important;
  1464. }
  1465. /* 统一所有输入框样式 */
  1466. .form-section .el-input {
  1467. width: 150px !important;
  1468. }
  1469. .form-section .el-input .el-input__inner {
  1470. height: 32px !important;
  1471. font-size: 13px !important;
  1472. border: 1px solid #dcdfe6 !important;
  1473. border-radius: 6px !important;
  1474. padding: 0 35px 0 12px !important;
  1475. transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) !important;
  1476. }
  1477. .form-section .el-input .el-input__inner:hover {
  1478. border-color: #c0c4cc !important;
  1479. }
  1480. .form-section .el-input .el-input__inner:focus {
  1481. border-color: #409eff !important;
  1482. outline: none !important;
  1483. box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1) !important;
  1484. }
  1485. .form-section .el-input .el-input__increase,
  1486. .form-section .el-input .el-input__decrease {
  1487. position: absolute !important;
  1488. right: 1px !important;
  1489. width: 32px !important;
  1490. height: 15px !important;
  1491. line-height: 15px !important;
  1492. background: #f5f7fa !important;
  1493. color: #606266 !important;
  1494. cursor: pointer !important;
  1495. font-size: 12px !important;
  1496. border: none !important;
  1497. border-radius: 0 !important;
  1498. transition: all 0.2s !important;
  1499. }
  1500. .form-section .el-input .el-input__increase {
  1501. top: 1px !important;
  1502. border-radius: 0 5px 0 0 !important;
  1503. }
  1504. .form-section .el-input .el-input__decrease {
  1505. bottom: 1px !important;
  1506. border-radius: 0 0 5px 0 !important;
  1507. }
  1508. .form-section .el-input .el-input__increase:hover,
  1509. .form-section .el-input .el-input__decrease:hover {
  1510. background: #e6a23c !important;
  1511. color: #fff !important;
  1512. }
  1513. .form-section .el-input .el-input__increase:active,
  1514. .form-section .el-input .el-input__decrease:active {
  1515. background: #cf9236 !important;
  1516. }
  1517. </style>