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.

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