index.vue 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <template>
  2. <div v-if="visible" class="forecast-form-container">
  3. <!-- 销售预测表单容器 - AvueJS版本 -->
  4. <div class="forecast-form-container basic-container">
  5. <!-- 表单内容区域 -->
  6. <div class="forecast-form-content">
  7. <avue-form
  8. ref="forecastForm"
  9. v-model="formData"
  10. :option="formOption"
  11. @submit="handleSubmit"
  12. @reset-change="handleReset"
  13. >
  14. <!-- 客户选择器插槽 -->
  15. <template #customerId>
  16. <customer-select
  17. v-model="formData.customerId"
  18. placeholder="请选择客户"
  19. @customer-selected="handleCustomerSelected"
  20. />
  21. </template>
  22. <!-- 预测年份插槽(使用 $refs.yearPicker 控制禁用) -->
  23. <template #year>
  24. <el-date-picker
  25. ref="yearPicker"
  26. v-model="formData.year"
  27. type="year"
  28. value-format="yyyy"
  29. placeholder="请选择年份"
  30. style="width: 100%"
  31. :disabled="isEdit"
  32. />
  33. </template>
  34. <!-- 预测月份插槽(使用 $refs.monthSelect 控制禁用) -->
  35. <template #month="{ column }">
  36. <el-select
  37. ref="monthSelect"
  38. v-model="formData.month"
  39. placeholder="请选择月份"
  40. style="width: 100%"
  41. :disabled="isEdit"
  42. >
  43. <el-option
  44. v-for="opt in (column && column.dicData) ? column.dicData : []"
  45. :key="opt.value"
  46. :label="opt.label"
  47. :value="opt.value"
  48. />
  49. </el-select>
  50. </template>
  51. </avue-form>
  52. <!-- 物料表格区域 -->
  53. <div class="forecast-goods-table">
  54. <div class="table-title">物料列表</div>
  55. <!-- 选择并导入物料工具栏 -->
  56. <div class="table-toolbar">
  57. <el-select
  58. v-model="selectedStockId"
  59. filterable
  60. clearable
  61. :disabled="stockSelectOptions.length === 0"
  62. placeholder="物料名称"
  63. style="width: 360px"
  64. >
  65. <el-option
  66. v-for="opt in stockSelectOptions"
  67. :key="opt.value"
  68. :label="opt.label"
  69. :value="opt.value"
  70. />
  71. </el-select>
  72. <el-button
  73. type="primary"
  74. :disabled="!selectedStockId"
  75. style="margin-left: 8px"
  76. @click="handleImportSelectedStock"
  77. >添加物料</el-button>
  78. <!-- 批量删除按钮:始终展示,无选中或加载中禁用 -->
  79. <el-button
  80. type="danger"
  81. icon="el-icon-delete"
  82. :disabled="tableLoading || !hasSelection"
  83. style="margin-left: 8px"
  84. @click="handleBatchDelete"
  85. >批量删除</el-button>
  86. </div>
  87. <el-table
  88. ref="stockTable"
  89. :data="pagedStockTableData"
  90. border
  91. stripe
  92. height="360"
  93. v-loading="tableLoading"
  94. :row-key="getRowUniqueKey"
  95. :reserve-selection="true"
  96. @selection-change="handleSelectionChange"
  97. >
  98. <el-table-column type="selection" width="48" />
  99. <el-table-column prop="code" label="物料编码" min-width="140" show-overflow-tooltip />
  100. <el-table-column prop="cname" label="物料名称" min-width="160" show-overflow-tooltip />
  101. <el-table-column prop="brandName" label="品牌名称" min-width="120" show-overflow-tooltip />
  102. <el-table-column prop="typeNo" label="规格" min-width="120" show-overflow-tooltip />
  103. <el-table-column prop="storeInventory" label="库存数量" min-width="120">
  104. <template #default="{ row }">
  105. <span>{{ parseInt(row.storeInventory || 0) }}</span>
  106. </template>
  107. </el-table-column>
  108. <!-- Removed specs/description column: productDescription -->
  109. <el-table-column label="预测数量" min-width="140">
  110. <template #default="{ row }">
  111. <el-input-number
  112. v-model="row.forecastQuantity"
  113. :min="0"
  114. :max="999999"
  115. :step="1"
  116. controls-position="right"
  117. style="width: 120px"
  118. />
  119. </template>
  120. </el-table-column>
  121. <!-- 操作列:删除按钮 -->
  122. <el-table-column label="操作" fixed="right" width="120">
  123. <template #default="{ row, $index }">
  124. <el-button
  125. type="text"
  126. size="small"
  127. icon="el-icon-delete"
  128. @click="handleDelete(row, $index)"
  129. >删除</el-button>
  130. </template>
  131. </el-table-column>
  132. </el-table>
  133. <!-- 分页控件(前端分页) -->
  134. <div class="table-pagination" style="margin-top: 8px; text-align: right;">
  135. <el-pagination
  136. :current-page="currentPage"
  137. :page-size="pageSize"
  138. :page-sizes="[5, 10, 20, 50, 100]"
  139. :total="total"
  140. layout="total, sizes, prev, pager, next, jumper"
  141. @current-change="handlePageChange"
  142. @size-change="handleSizeChange"
  143. />
  144. </div>
  145. <div class="table-tip">提示:先在上方选择物料并点击“导入物料”,导入后的数据将显示在表格并参与保存流程。</div>
  146. </div>
  147. </div>
  148. </div>
  149. </div>
  150. </template>
  151. <script>
  152. import forecastFormMixin from './forecast-form-mixin.js'
  153. import CustomerSelect from '@/components/common/customer-select.vue'
  154. /**
  155. * 销售预测表单组件实例类型定义
  156. * @typedef {object} ForecastFormAvueComponent
  157. * @property {import('./types').ForecastFormModel} formData - 表单数据
  158. * @property {import('./types').FormOption} formOption - 表单配置选项
  159. * @property {boolean} saveLoading - 保存加载状态
  160. * @property {import('./types').CustomerOption[]} customerOptions - 客户选项列表
  161. * @property {number|null} currentInventory - 当前库存数量
  162. * @property {import('./types').ApprovalStatusOption[]} approvalStatusOptions - 审批状态选项
  163. * @property {import('./types').ForecastFormRules} formRules - 表单验证规则
  164. * @property {boolean} visible - 表单可见性
  165. * @property {boolean} isEdit - 是否为编辑模式
  166. * @property {Object|null} editData - 编辑数据
  167. * @property {Object|null} initialFormData - 初始表单数据
  168. * @property {string} title - 表单标题
  169. * @property {string} forecastId - 预测ID
  170. */
  171. /**
  172. * 销售预测表单组件 - AvueJS版本
  173. * @description 基于AvueJS的销售预测表单组件,支持新增和编辑销售预测功能
  174. */
  175. export default {
  176. name: 'ForecastFormAvue',
  177. mixins: [forecastFormMixin],
  178. /**
  179. * 组件注册
  180. */
  181. components: {
  182. CustomerSelect
  183. },
  184. /**
  185. * @this {import('./types').ForecastFormMixinComponent & Vue}
  186. */
  187. mounted() {
  188. // 在编辑态,初始禁用“年份/月份”两个控件(通过 $refs 设置)
  189. this.$nextTick(() => {
  190. try {
  191. if (this.isEdit) {
  192. if (this.$refs.yearPicker) { /** @type {any} */ (this.$refs.yearPicker).disabled = true }
  193. if (this.$refs.monthSelect) { /** @type {any} */ (this.$refs.monthSelect).disabled = true }
  194. }
  195. } catch (e) {
  196. // 忽略可能的非关键性异常
  197. }
  198. })
  199. },
  200. methods: {
  201. // 通过 $refs 统一设置“年份/月份”的禁用状态
  202. /** @param {boolean} disabled */
  203. setYearMonthDisabled(disabled) {
  204. this.$nextTick(() => {
  205. try {
  206. if (this.$refs.yearPicker) { /** @type {any} */ (this.$refs.yearPicker).disabled = disabled }
  207. if (this.$refs.monthSelect) { /** @type {any} */ (this.$refs.monthSelect).disabled = disabled }
  208. } catch (e) {
  209. // 忽略可能的非关键性异常
  210. }
  211. })
  212. }
  213. }
  214. }
  215. </script>
  216. <style lang="scss" scoped>
  217. @import './index.scss';
  218. .forecast-goods-table {
  219. margin-top: 12px;
  220. }
  221. .table-title {
  222. font-size: 14px;
  223. color: #333;
  224. margin-bottom: 8px;
  225. }
  226. .table-toolbar {
  227. margin-bottom: 8px;
  228. }
  229. .table-tip {
  230. margin-top: 8px;
  231. font-size: 12px;
  232. color: #909399;
  233. }
  234. </style>