index.vue 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. <template>
  2. <div class="app-container">
  3. <div class="filter-container">
  4. <!-- <el-select v-model="list.main.query.baseUnit" class="filter-item" size="mini" placeholder="食物类型" style="width:150px;margin-right:5px;" clearable>
  5. <el-option label="是" :value="true" />
  6. <el-option label="否" :value="false" />
  7. </el-select>
  8. <el-select v-model="list.main.query.baseUnit" class="filter-item" size="mini" placeholder="食物类别" style="width:150px;margin-right:5px;" clearable>
  9. <el-option label="是" :value="true" />
  10. <el-option label="否" :value="false" />
  11. </el-select>
  12. <el-input v-model="list.main.query.name" class="filter-item" size="mini" placeholder="名称" style="width:150px;margin-right:5px;" clearable />
  13. <el-input v-model="list.main.query.enName" class="filter-item" size="mini" placeholder="英文名称" style="width:150px;margin-right:5px;" clearable />
  14. <el-select v-model="list.main.query.baseUnit" class="filter-item" size="mini" placeholder="状态" style="width:150px;margin-right:5px;" clearable>
  15. <el-option label="是" :value="true" />
  16. <el-option label="否" :value="false" />
  17. </el-select> -->
  18. <el-button class="filter-item" size="mini" type="primary" @click="M.list()">查询</el-button>
  19. <el-button class="filter-item" size="mini" @click="() => {M.reset({ data: { page: 1, limit: list.main.query.limit } })}">重置</el-button>
  20. <div style="float:right;">
  21. <el-button class="filter-item" size="mini" type="success" style="margin-right:15px;" @click="create">新增</el-button>
  22. </div>
  23. </div>
  24. <el-table v-loading="list.main.loading" :data="list.main.list" border fit highlight-current-row style="width:100%" :max-height="maxHeight">
  25. <!-- <el-table-column width="50" header-align="center" label="权重">
  26. <template slot-scope="{row}">
  27. <span>{{ row.sortOrder }}</span>
  28. </template>
  29. </el-table-column> -->
  30. <el-table-column width="70" align="center" label="图片">
  31. <template slot-scope="{row}">
  32. <el-image v-if="row.mainImage" style="width:50px;height:50px;" :src="row.mainImage" fit="contain" />
  33. </template>
  34. </el-table-column>
  35. <el-table-column min-width="150" header-align="center" label="名称">
  36. <template slot-scope="{row}">
  37. <el-tag v-if="!!row.typeName" size="mini" effect="plain">{{ row.typeName }}</el-tag><span>{{ row.name }}</span>
  38. </template>
  39. </el-table-column>
  40. <el-table-column min-width="180" header-align="center" label="英文名称">
  41. <template slot-scope="{row}">
  42. <span>{{ row.enName }}</span>
  43. </template>
  44. </el-table-column>
  45. <el-table-column width="80" header-align="center" align="right" label="可食部(%)">
  46. <template slot-scope="{row}">
  47. <span v-if="row.ep>0">{{ row.ep }}%</span>
  48. <span v-else>-</span>
  49. </template>
  50. </el-table-column>
  51. <el-table-column width="80" header-align="center" align="right" label="GI">
  52. <template slot-scope="{row}">
  53. <span>{{ row.gi }}</span>
  54. </template>
  55. </el-table-column>
  56. <el-table-column width="80" header-align="center" align="right" label="GL">
  57. <template slot-scope="{row}">
  58. <span>{{ row.gl }}</span>
  59. </template>
  60. </el-table-column>
  61. <el-table-column width="100" align="center" label="来源">
  62. <template slot-scope="{row}">
  63. <span>{{ row.source }}</span>
  64. </template>
  65. </el-table-column>
  66. <el-table-column width="60" align="center" label="状态">
  67. <template slot-scope="{row}">
  68. <span v-if="row.shelfStatus=='ONLINE'" style="color:green;">上架</span>
  69. <span v-else style="color:gray;">下架</span>
  70. </template>
  71. </el-table-column>
  72. <el-table-column width="80" align="center" label="创建人">
  73. <template slot-scope="{row}">
  74. <span>{{ row.userName || '-' }}</span>
  75. </template>
  76. </el-table-column>
  77. <el-table-column width="140" align="center" label="创建时间">
  78. <template slot-scope="{row}">
  79. <span>{{ row.createTime }}</span>
  80. </template>
  81. </el-table-column>
  82. <el-table-column width="140" align="center" label="更新时间">
  83. <template slot-scope="{row}">
  84. <span>{{ row.updateTime }}</span>
  85. </template>
  86. </el-table-column>
  87. <el-table-column width="60" align="center" label="操作" fixed="right">
  88. <template slot-scope="{row}">
  89. <i class="el-icon-edit" style="cursor:pointer;color:#999999;margin-right:5px;" @click="edit(row)"></i>
  90. &nbsp;&nbsp;
  91. <i class="el-icon-delete" style="cursor:pointer;color:#999999;m"></i>
  92. </template>
  93. </el-table-column>
  94. </el-table>
  95. <pagination v-show="list.main.total>0" :total="list.main.total" :page.sync="list.main.query.page" :limit.sync="list.main.query.limit" @pagination="M.list()" />
  96. <el-dialog :title="dlg.form.title" :visible.sync="dlg.form.visible" width="95%" top="3vh">
  97. <el-form ref="form" :rules="dlg.form.rules" :model="dlg.form.data" size="mini" label-position="right" label-width="100px">
  98. <el-tabs v-model="dlg.form.infoTab" @tab-click="foodInfoTabClick">
  99. <el-tab-pane label="食物基本信息" name="base">
  100. <el-row :gutter="10">
  101. <el-col :span="6">
  102. <el-form-item label="名称" prop="name">
  103. <el-input v-model="dlg.form.data.name" placeholder="请输入食物名称,不能重复" />
  104. </el-form-item>
  105. </el-col>
  106. <el-col :span="6">
  107. <el-form-item label="主/辅料" prop="type">
  108. <el-select v-model="dlg.form.data.type" class="filter-item" size="mini" placeholder="请选择主/辅料" style="width:100%;">
  109. <el-option label="主料" value="MAIN" />
  110. <el-option label="辅料" value="SUB" />
  111. </el-select>
  112. </el-form-item>
  113. </el-col>
  114. <el-col :span="6">
  115. <el-form-item label="食物形态">
  116. <el-select v-model="dlg.form.data.som" class="filter-item" size="mini" placeholder="请选择食物形态" style="width:70%;">
  117. <el-option label="固态" value="SOLID" />
  118. <el-option label="液态" value="LIQUID" />
  119. </el-select>
  120. <el-checkbox v-model="dlg.form.data.isGranular" style="float:right;">颗粒状</el-checkbox>
  121. </el-form-item>
  122. </el-col>
  123. <el-col :span="6">
  124. <el-form-item label="食物类别">
  125. <el-input v-model="dlg.form.data.categoryId" placeholder="请选择食物类别" />
  126. </el-form-item>
  127. </el-col>
  128. </el-row>
  129. <el-row :gutter="10">
  130. <el-col :span="6">
  131. <el-form-item label="可食部">
  132. <el-input v-model="dlg.form.data.ep" :min="0" :max="100" placeholder="可食部(0~100%)">
  133. <span slot="append">%</span>
  134. </el-input>
  135. </el-form-item>
  136. </el-col>
  137. <el-col :span="6">
  138. <el-form-item label="[计算]可食部">
  139. <el-input v-model="dlg.form.data.calcEp" :min="0" :max="100" placeholder="计算用可食部(0~100%)">
  140. <span slot="append">%</span>
  141. </el-input>
  142. </el-form-item>
  143. </el-col>
  144. <el-col :span="6">
  145. <el-form-item label="GI">
  146. <el-input v-model="dlg.form.data.gi" placeholder="请输入GI" />
  147. </el-form-item>
  148. </el-col>
  149. <el-col :span="6">
  150. <el-form-item label="GL">
  151. <el-input v-model="dlg.form.data.gl" placeholder="请输入GL" />
  152. </el-form-item>
  153. </el-col>
  154. </el-row>
  155. <el-row :gutter="10">
  156. <el-col :span="8">
  157. <el-form-item label="密度">
  158. <el-input v-model="dlg.form.data.densityVolumeAmt" placeholder="体积" style="width:60px;" />
  159. <DataSelect
  160. url="/api/volume-units"
  161. placeholder="体积单位"
  162. :value.sync="dlg.form.data.densityVolumeUnitId"
  163. :label.sync="dlg.form.data.densityVolumeUnit"
  164. width="130px;margin-left:1px;"
  165. />
  166. <span style="color:red;font-size:14px;font-weight:700;">&nbsp;=&nbsp;</span>
  167. <el-input v-model="dlg.form.data.densityAmt" placeholder="质量" style="width:60px;" />
  168. <DataSelect
  169. url="/api/mass-units"
  170. placeholder="质量单位"
  171. :value.sync="dlg.form.data.densityUnitId"
  172. :label.sync="dlg.form.data.densityUnit"
  173. width="130px;margin-left:1px;"
  174. />
  175. </el-form-item>
  176. </el-col>
  177. <el-col :span="8">
  178. <el-form-item label="堆密度">
  179. <el-input v-model="dlg.form.data.bulkDensityVolumeAmt" placeholder="体积" style="width:60px;" />
  180. <DataSelect
  181. url="/api/volume-units"
  182. placeholder="体积单位"
  183. :value.sync="dlg.form.data.bulkDensityVolumeUnitId"
  184. :label.sync="dlg.form.data.bulkDensityVolumeUnit"
  185. width="130px;margin-left:1px;"
  186. />
  187. <span style="color:red;font-size:14px;font-weight:700;">&nbsp;=&nbsp;</span>
  188. <el-input v-model="dlg.form.data.bulkDensityAmt" placeholder="堆密度" style="width:60px;" />
  189. <DataSelect
  190. url="/api/units"
  191. placeholder="堆密度单位"
  192. :value.sync="dlg.form.data.bulkDensityUnitId"
  193. :label.sync="dlg.form.data.bulkDensityUnit"
  194. width="130px;margin-left:1px;"
  195. />
  196. </el-form-item>
  197. </el-col>
  198. <el-col :span="8">
  199. <el-form-item label="[计算]密度">
  200. <el-input v-model="dlg.form.data.calcDensityVolumeAmt" placeholder="体积" style="width:60px;" />
  201. <DataSelect
  202. url="/api/volume-units"
  203. placeholder="体积单位"
  204. :value.sync="dlg.form.data.calcDensityVolumeUnitId"
  205. :label.sync="dlg.form.data.calcDensityVolumeUnit"
  206. width="130px;margin-left:1px;"
  207. />
  208. <span style="color:red;font-size:14px;font-weight:700;">&nbsp;=&nbsp;</span>
  209. <el-input v-model="dlg.form.data.calcDensityAmt" placeholder="质量" style="width:60px;" />
  210. <DataSelect
  211. url="/api/mass-units"
  212. placeholder="质量单位"
  213. :value.sync="dlg.form.data.calcDensityUnitId"
  214. :label.sync="dlg.form.data.calcDensityUnit"
  215. width="130px;margin-left:1px;"
  216. />
  217. </el-form-item>
  218. </el-col>
  219. </el-row>
  220. <el-form-item label="描述">
  221. <el-input v-model="dlg.form.data.code" type="textarea" rows="3" placeholder="请输入单位编码,可为空,但不能重复" />
  222. </el-form-item>
  223. <el-form-item label="食物图">
  224. </el-form-item>
  225. <el-form-item label="营养素图">
  226. </el-form-item>
  227. <el-form-item label="其他图">
  228. </el-form-item>
  229. </el-tab-pane>
  230. <el-tab-pane label="规格" name="modifier">
  231. <div style="margin-bottom:5px;">
  232. <el-button size="mini" type="primary" plain @click="addModifier(dlg.form.data)">添加</el-button>
  233. </div>
  234. <el-table :data="dlg.form.data.modifiers" :show-header="false" border fit highlight-current-row style="width:100%">
  235. <el-table-column type="index" width="50" align="center" />
  236. <el-table-column>
  237. <template slot-scope="{row}">
  238. <span v-if="row._edit">
  239. <el-input v-model="row.name" placeholder="规格名称" style="width:130px;margin-right:5px;" @change="modifierUnitChange" />
  240. <DataSelect
  241. url="/api/units"
  242. placeholder="规格单位"
  243. :value.sync="row.unitId"
  244. :label.sync="row.unitName"
  245. width="100px"
  246. :allowCreate="true"
  247. @select="modifierUnitChange"
  248. />
  249. [
  250. <span style="color:blue;font-size:13px;">&nbsp;规格转换:&nbsp;</span>
  251. <el-input v-model="row.toModifierInput" placeholder="数量" style="width:60px;" />
  252. <span>{{ row.key || '' }}</span>
  253. <span style="color:red;font-size:14px;font-weight:700;">&nbsp;=&nbsp;</span>
  254. <el-input v-model="row.toModifierAmt" placeholder="数量" style="width:60px;margin-right:10px;" />
  255. <el-select v-model="row.toModifierName" class="filter-item" placeholder="规格单位" style="width:120px" clearable>
  256. <el-option v-for="opt in dlg.form.modifierUnitOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
  257. </el-select>
  258. ]
  259. [
  260. <span style="color:blue;font-size:13px;">&nbsp;标准单位转换:&nbsp;</span>
  261. <el-input v-model="row.stdMeasureInput" placeholder="数量" style="width:60px;" />
  262. <span>{{ row.key || '' }}</span>
  263. <span style="color:red;font-size:14px;font-weight:700;">&nbsp;=&nbsp;</span>
  264. <el-input v-model="row.stdMeasureAmt" placeholder="数量" style="width:60px;margin-right:10px;" />
  265. <DataSelect
  266. url="/api/units"
  267. placeholder="标准单位"
  268. :value.sync="row.stdMeasureUnitId"
  269. :label.sync="row.stdMeasureUnit"
  270. width="90px"
  271. />
  272. ]
  273. [
  274. <span style="color:blue;font-size:13px;">&nbsp;推荐量:&nbsp;</span>
  275. <el-input v-model="row.inInit" placeholder="数量" style="width:60px;" />
  276. <DataSelect
  277. url="/api/units"
  278. placeholder="推荐量单位"
  279. :value.sync="row.inInitUnitId"
  280. :label.sync="row.inInitUnit"
  281. :initOptions="dlg.form.modifierUnitOptions"
  282. width="90px"
  283. />
  284. ]
  285. <br>
  286. <el-checkbox v-model="row.isBiteSized" label='isBiteSized'></el-checkbox>
  287. <el-checkbox v-model="row.isServing" label='isServing'></el-checkbox>
  288. <el-checkbox v-model="row.isPrepackaged" label='isPrepackaged'></el-checkbox>
  289. <el-checkbox v-model="row.isRealSku" label='isRealSku'></el-checkbox>
  290. </span>
  291. <span v-else>
  292. -
  293. </span>
  294. </template>
  295. </el-table-column>
  296. <el-table-column width="90" align="center">
  297. <template slot-scope="{$index}">
  298. <i class="el-icon-delete" style="cursor:pointer;color:#999999;margin-right:5px;" @click="fn.remove(dlg.form.data.modifiers, $index)"></i>
  299. &nbsp;&nbsp;
  300. <i class="el-icon-top" style="cursor:pointer;color:#999999;margin-right:5px;" @click="fn.moveUp(dlg.form.data.modifiers, $index)"></i>
  301. &nbsp;&nbsp;
  302. <i class="el-icon-bottom" style="cursor:pointer;color:#999999;" @click="fn.moveDown(dlg.form.data.modifiers, $index)"></i>
  303. </template>
  304. </el-table-column>
  305. </el-table>
  306. </el-tab-pane>
  307. <el-tab-pane label="营养素" name="nutrient">
  308. <div style="margin-bottom:5px;">
  309. <span>
  310. <el-button size="mini" type="primary" plain @click="addNutrient(dlg.form.data)">添加</el-button>
  311. </span>
  312. <el-select v-model="dlg.form.selectedNutrientTemplate" class="filter-item" style="margin-left: 10%; display: float; margin-right: 0.5%" v-on:input.native="getNutrienttemplateList($event, dlg.form)" filterable placeholder="请输入检索词">
  313. <el-option v-for="opt in dlg.form.nutrientTemplateOptions" :key="opt.id" :label="opt.name" :value="opt.name" />
  314. </el-select>
  315. <el-button size="mini" type="primary" plain @click="importNutrientTemplate()">导入营养素模版</el-button>
  316. </div>
  317. <el-table :data="dlg.form.data.nutrients" :show-header="false" border fit highlight-current-row style="width:100%">
  318. <el-table-column type="index" width="50" align="center" />
  319. <el-table-column>
  320. <template slot-scope="{row}">
  321. <span v-if="row._edit">
  322. <DataSelect
  323. url="/api/nutrients"
  324. placeholder="请选择营养素"
  325. width="130px;margin-right:5px;"
  326. :value.sync="row.nutrientId"
  327. :label.sync="row.nutrientName"
  328. @select="(nutrient) => nutrientSelect(nutrient, row)"
  329. />
  330. <el-select v-model="row.nvMeasureMode" size="mini" placeholder="计量" style="width:80px;margin-right:5px;">
  331. <el-option label="值" value="VALUE" />
  332. <el-option label="范围" value="RANGE" />
  333. <el-option label="误差" value="ADJUST" />
  334. </el-select>
  335. <span style="color:red;font-size:15px;font-weight:700;">(</span>
  336. <span v-if="row.nvMeasureMode=='VALUE'">
  337. <el-input v-model="row.nv" placeholder="取值" style="width:70px;margin-right:10px;" />
  338. </span>
  339. <span v-else-if="row.nvMeasureMode=='RANGE'">
  340. <el-input v-model="row.nvMin" placeholder="最小值" style="width:70px;margin-right:10px;" />
  341. -
  342. <el-input v-model="row.nvMax" placeholder="最大值" style="width:70px;margin-right:10px;" />
  343. </span>
  344. <span v-else-if="row.nvMeasureMode=='ADJUST'">
  345. <el-input v-model="row.nv" placeholder="取值" style="width:70px;margin-right:10px;" />
  346. <el-input v-model="row.nv_adjust" placeholder="误差" style="width:80px;margin-right:10px;">
  347. <span slot="prepend">±</span>
  348. </el-input>
  349. </span>
  350. <el-select v-model="row.nvUnitId" placeholder="营养素单位" style="width:100px" clearable>
  351. <el-option v-if="!!row.nvUnitId && row._nutrientUnitOptions && !row._nutrientUnitOptions.find(v => v.value == row.nvUnitId)" :key="row.nvUnitId" :label="row.nvUnit" :value="row.nvUnitId" />
  352. <el-option v-for="opt in row._nutrientUnitOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
  353. <el-option v-for="opt in dlg.form.data.nutrients" :key="opt.nvUnitId" :label="opt.nvUnit" :value="opt.nvUnitId" />
  354. </el-select>
  355. <span style="color:red;font-weight:700;">&nbsp;/&nbsp;</span>
  356. <el-input v-model="row.nvSpec" placeholder="nv_spec" style="width:70px;margin-right:10px;" />
  357. <DataSelect
  358. url="/api/units"
  359. placeholder="nv_spec单位"
  360. :value.sync="row.nvSpecUnitId"
  361. :label.sync="row.nvSpecUnit"
  362. width="110px"
  363. :allowCreate="true"
  364. :initOptions="dlg.form.modifierUnitOptions"
  365. />
  366. <span style="color:red;font-size:15px;font-weight:700;">)</span>
  367. <!-- [
  368. <span style="color:green;font-weight:700;">1</span>&nbsp;<span style="color:red">{{ row.nvSpecUnit }}</span>
  369. &nbsp;*&nbsp;
  370. <el-input v-model="row.cfNvUnitToBaseUnit" style="width:80px;margin-right:5px;" />
  371. =&nbsp;*&nbsp; 1 {{ row.nutrient && row.nutrient.baseUnitName || '基础单位' }}
  372. ] -->
  373. </span>
  374. <span v-else>
  375. </span>
  376. </template>
  377. </el-table-column>
  378. <el-table-column width="90" align="center">
  379. <template slot-scope="{$index}">
  380. <i class="el-icon-delete" style="cursor:pointer;color:#999999;margin-right:5px;" @click="fn.remove(dlg.form.data.nutrients, $index)"></i>
  381. &nbsp;&nbsp;
  382. <i class="el-icon-top" style="cursor:pointer;color:#999999;margin-right:5px;" @click="fn.moveUp(dlg.form.data.nutrients, $index)"></i>
  383. &nbsp;&nbsp;
  384. <i class="el-icon-bottom" style="cursor:pointer;color:#999999;" @click="fn.moveDown(dlg.form.data.nutrients, $index)"></i>
  385. </template>
  386. </el-table-column>
  387. </el-table>
  388. </el-tab-pane>
  389. <el-tab-pane label="CF" name="cf">
  390. <el-tag v-if="dlg.form.data.calcDensityAmt>0&&dlg.form.data.calcDensityVolumeAmt>0" style="margin-bottom:5px;">
  391. {{ dlg.form.data.calcDensityAmt }}{{ dlg.form.data.calcDensityUnit }}={{ dlg.form.data.calcDensityVolumeAmt }}{{ dlg.form.data.calcDensityVolumeUnit }}
  392. </el-tag>
  393. <el-table :data="dlg.form.data.cfs" border fit highlight-current-row style="width:100%">
  394. <el-table-column type="index" width="50" align="center" />
  395. <el-table-column min-width="180" header-align="center" label="源单位">
  396. <template slot-scope="{row}">
  397. <span>{{ row.fromUnit }}</span>
  398. </template>
  399. </el-table-column>
  400. <el-table-column min-width="180" header-align="center" label="转换后单位">
  401. <template slot-scope="{row}">
  402. <span>{{ row.toUnit }}</span>
  403. </template>
  404. </el-table-column>
  405. <el-table-column min-width="210" header-align="center" label="转换关系">
  406. <template slot-scope="{row}">
  407. <span v-if="row.edit">
  408. <span v-if="row._edit">
  409. 1 {{ row.fromUnit }} *
  410. <el-input v-model="row.cf" style="width:100px;margin-right:10px;" />
  411. =1 {{ row.toUnit }}
  412. <i class="el-icon-check" style="cursor:pointer;color:green;font-size:15px;" @click="saveCf(row)" />
  413. </span>
  414. <span v-else>
  415. 1 {{ row.fromUnit }} * {{ row.cf }} = 1 {{ row.toUnit }}
  416. <i class="el-icon-edit" style="cursor:pointer;color:blue;font-size:15px;" @click="row._edit=true" />
  417. </span>
  418. </span>
  419. <span v-else>
  420. 1 {{ row.fromUnit }} * {{ row.cf }} = 1 {{ row.toUnit }}
  421. </span>
  422. </template>
  423. </el-table-column>
  424. </el-table>
  425. </el-tab-pane>
  426. <el-tab-pane label="营养素含量计算" name="calc">
  427. <div>
  428. <el-input v-model="calc.req.amt" placeholder="摄入量" style="width:100px;margin-right:10px;" />
  429. <DataSelect
  430. url="/api/units"
  431. placeholder="摄入量单位"
  432. :value.sync="calc.req.unitId"
  433. :label.sync="calc.req.unitName"
  434. :initOptions="dlg.form.modifierUnitOptions"
  435. width="110px"
  436. />
  437. <el-button :loading="calc.loading" size="mini" type="success" style="margin-left:15px;" @click="calcNvIn">计算</el-button>
  438. <span>
  439. {{ calc.rsp.amt }}{{ calc.rsp.unitName }}
  440. </span>
  441. </div>
  442. <div style="margin-top:5px;">
  443. <p v-for="nv in calc.rsp.nvList" :key="nv.name">{{ nv.name }} 摄入:{{ nv.nvIn }}{{ nv.nvUnit }}, ({{ nv.nv }}{{ nv.nvUnit }}/{{ nv.nvSpec }}{{ nv.nvSpecUnit }})</p>
  444. </div>
  445. <div style="margin-top:5px;">
  446. <el-input v-model="cf.req.fromAmt" placeholder="源单位数量" style="width:100px;margin-right:10px;" />
  447. <DataSelect
  448. url="/api/units"
  449. placeholder="源单位"
  450. :value.sync="cf.req.fromUnitId"
  451. :label.sync="cf.req.fromUnit"
  452. :initOptions="dlg.form.modifierUnitOptions"
  453. width="110px"
  454. />
  455. -
  456. <DataSelect
  457. url="/api/units"
  458. placeholder="目标单位"
  459. :value.sync="cf.req.toUnitId"
  460. :label.sync="cf.req.toUnit"
  461. :initOptions="dlg.form.modifierUnitOptions"
  462. width="110px"
  463. />
  464. <el-button :loading="cf.loading" size="mini" type="success" style="margin-left:15px;" @click="calcCf">计算转换</el-button>
  465. </div>
  466. <div>
  467. <span v-if="!!cf.rsp.error">
  468. {{ cf.rsp.error }}
  469. </span>
  470. <span v-else-if="cf.rsp.steps.length>0">
  471. <div style="margin-bottom:5px;">
  472. {{ cf.rsp.fromAmt }}{{ cf.rsp.fromUnit }} * {{ cf.rsp.cf }} = {{ cf.rsp.toAmt }}{{ cf.rsp.toUnit }}
  473. </div>
  474. <div v-for="step in cf.rsp.steps" :key="step.convert.fromUnit" style="margin-bottom:5px;">
  475. 【1{{ step.convert.fromUnit }} * {{ step.convert.cf }} = 1{{ step.convert.toUnit }},{{ step.cf }}】
  476. {{ step.fromAmt }}{{ step.convert.fromUnit }} * {{ step.convert.cf }} = {{ step.toAmt }}{{ step.convert.toUnit }}
  477. </div>
  478. </span>
  479. </div>
  480. </el-tab-pane>
  481. </el-tabs>
  482. </el-form>
  483. <div slot="footer" class="dialog-footer">
  484. <el-button size="mini" @click="dlg.form.visible = false">
  485. 取消
  486. </el-button>
  487. <el-button :loading="dlg.form.saveLoading" size="mini" type="primary" @click="onlySave">
  488. 仅保存
  489. </el-button>
  490. <el-button :loading="dlg.form.saveLoading" size="mini" type="primary" @click="M.save()">
  491. 保存并退出
  492. </el-button>
  493. </div>
  494. </el-dialog>
  495. </div>
  496. </template>
  497. <script>
  498. import Pagination from '@/components/Pagination'
  499. import { fGet, fPost, fSave } from '@/api/rest'
  500. import { M } from '@/api/op'
  501. import DataSelect from '@/views/components/DataSelect/index'
  502. import fn from '@/api/fn'
  503. export default {
  504. components: { Pagination, DataSelect },
  505. data() {
  506. return {
  507. M: new M(this),
  508. fn,
  509. URI: '/api/foods',
  510. maxHeight: 600,
  511. baseUnitOptions: [],
  512. tempList: [{
  513. _edit: true
  514. },{}],
  515. list: {
  516. main: {
  517. loading: true,
  518. total: 0,
  519. list: [],
  520. render(row) {
  521. row.modifiers = row.modifiers || []
  522. row.nutrients = row.nutrients || []
  523. row.modifiers && row.modifiers.forEach(v => v._edit = true)
  524. row.nutrients && row.nutrients.forEach(v => {
  525. v._edit = true
  526. v._nutrientUnitOptions = []
  527. })
  528. row.cfs = row.cfs || []
  529. row.cfs && row.cfs.forEach(v => {
  530. v._edit = false
  531. })
  532. return row
  533. },
  534. query: {
  535. page: 1,
  536. limit: 50
  537. }
  538. }
  539. },
  540. calc: {
  541. loading: false,
  542. req: {
  543. amt: undefined,
  544. unitId: undefined,
  545. unitName: undefined
  546. },
  547. rsp: {
  548. amt: undefined,
  549. unitName: undefined,
  550. nvList: []
  551. }
  552. },
  553. cf: {
  554. loading: false,
  555. req: {
  556. fromAmt: undefined,
  557. fromUnitId: undefined,
  558. fromUnit: undefined,
  559. toUnitId: undefined,
  560. toUnit: undefined
  561. },
  562. rsp: {
  563. steps: []
  564. }
  565. },
  566. dlg: {
  567. form: {
  568. infoTab: 'base',
  569. visible: false,
  570. title: '',
  571. data: {
  572. modifiers: [],
  573. nutrients: []
  574. },
  575. saveLoading: false,
  576. modifierUnitOptions: [],
  577. rules: {
  578. // type: [{ required: true, message: '请选择主/辅料', trigger: 'blur' }],
  579. name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
  580. }
  581. }
  582. }
  583. }
  584. },
  585. created() {
  586. this.maxHeight = document.documentElement.clientHeight - 135
  587. this.M.list()
  588. },
  589. methods: {
  590. // 加载详细信息
  591. loadDetail(id) {
  592. fGet(`${this.URI}/${id}`).then(res => {
  593. const detail = {
  594. ...res
  595. }
  596. detail.modifiers && detail.modifiers.forEach(v => v._edit = true)
  597. detail.nutrients && detail.nutrients.forEach(v => {
  598. v._edit = true
  599. v._nutrientUnitOptions = []
  600. })
  601. detail.cfs && detail.cfs.forEach(v => {
  602. v._edit = false
  603. })
  604. this.dlg.form.data = detail
  605. this.modifierUnitChange()
  606. })
  607. },
  608. // 新增
  609. create() {
  610. this.dlg.form.modifierUnitOptions = []
  611. this.M.create({ form: 'form', title: '新增', data: {} })
  612. },
  613. // 编辑
  614. edit(row) {
  615. this.dlg.form.modifierUnitOptions = []
  616. this.M.edit({ form: 'form', title: 'name', row: row })
  617. this.loadDetail(row.id)
  618. },
  619. // 自定义单位判断
  620. isCustomUnit(id, name) {
  621. return !!name && name.trim().length > 0 && (!id || id == 'CUSTOM_UNIT' || id.length == 0 || id == name)
  622. },
  623. // 规格单位列表生成
  624. modifierUnitChange() {
  625. const modifierUnitOptions = []
  626. const modifierUnitInclude = {}
  627. this.dlg.form.data.modifiers.forEach(modifier => {
  628. const unitId = modifier.unitId || ''
  629. const unitName = modifier.unitName || ''
  630. if (this.isCustomUnit(unitId, unitName)) {
  631. const name = modifier.name || ''
  632. if (!!(modifier.unitName) && modifier.unitName.trim().length > 0) {
  633. modifier.key = (unitName == name ? unitName : `${unitName}${name}`)
  634. modifierUnitOptions.push({
  635. label: modifier.key,
  636. value: modifier.key
  637. })
  638. modifierUnitInclude[modifier.key] = true
  639. }
  640. } else {
  641. modifier.key = unitName
  642. }
  643. })
  644. this.dlg.form.data.modifiers.forEach(modifier => {
  645. if (!!(modifier.toModifierName) && !modifierUnitInclude[modifier.toModifierName]) {
  646. modifier.toModifierId = undefined
  647. modifier.toModifierName = undefined
  648. }
  649. })
  650. this.dlg.form.modifierUnitOptions = modifierUnitOptions
  651. },
  652. // 添加规格
  653. addModifier(row) {
  654. row.modifiers.push({
  655. _edit: true,
  656. })
  657. },
  658. // 删除规格
  659. removeModifier(row, index) {
  660. row.modifiers.splice(index, 1)
  661. },
  662. // 添加营养素
  663. addNutrient(row) {
  664. row.nutrients.push({
  665. _edit: true,
  666. _nutrientUnitOptions: []
  667. })
  668. },
  669. // 删除营养素
  670. removeNutrient(row, index) {
  671. row.nutrients.splice(index, 1)
  672. },
  673. // 导入营养素模版
  674. importNutrientTemplate() {
  675. console.log(this.dlg.form.data.nutrients)
  676. if (this.dlg.form.selectedNutrientTemplate == undefined) {
  677. return
  678. }
  679. if (this.dlg.form.data.nutrients == undefined) {
  680. this.dlg.form.data.nutrients = []
  681. }
  682. this.dlg.form.nutrientTemplateOptions.forEach(opt => {
  683. if (opt.name == this.dlg.form.selectedNutrientTemplate) {
  684. this.dlg.form.selectedNutrientTemplateId = opt.id
  685. }
  686. })
  687. fGet(`/api/nutrient-templates/${this.dlg.form.selectedNutrientTemplateId}/nutrients`, {}).then(res => {
  688. if (res == undefined) {return}
  689. let existed = false
  690. // 渲染营养素
  691. res.forEach(nv => {
  692. // 筛选营养素
  693. this.dlg.form.data.nutrients.forEach(existNv => {
  694. if (nv.nutrientId == existNv.nutrientId) {
  695. existed = true
  696. }
  697. })
  698. if (! existed) {
  699. this.dlg.form.data.nutrients.push({
  700. _edit: true,
  701. _nutrientUnitOptions: [],
  702. nutrientId: nv.nutrientId,
  703. nutrientName: nv.nutrientName,
  704. nvUnit: nv.unit,
  705. nvSpec: nv.nvSpec,
  706. nvSpecUnit: nv.nvSpecUnit,
  707. nvSpecUnitId: nv.nvSpecUnitId,
  708. nvUnitId: nv.unitId,
  709. nvMeasureMode: nv.quantityType
  710. })
  711. }
  712. })
  713. })
  714. },
  715. getNutrienttemplateList(e, row) {
  716. row.nutrientTemplateOptions = []
  717. fGet(`/api/nutrient-templates`, {keyword: e.target.value}).then(res => {
  718. this.$set(row, 'nutrientTemplateOptions', res)
  719. console.log(row.nutrientTemplateOptions)
  720. })
  721. },
  722. // 营养素选择
  723. nutrientSelect(nutrient, row) {
  724. row._nutrientUnitOptions = []
  725. if (nutrient._data && nutrient._data.unitName) {
  726. row._nutrientUnitOptions.push({
  727. value: nutrient._data.unitId == 'CUSTOM_UNIT' ? nutrient._data.unitName : nutrient._data.unitId,
  728. label: nutrient._data.unitName
  729. })
  730. }
  731. if (nutrient._data && nutrient._data.optionUnits) {
  732. nutrient._data.optionUnits.forEach(optionUnit => {
  733. row._nutrientUnitOptions.push({
  734. value: optionUnit.unitId == 'CUSTOM_UNIT' ? optionUnit.name : optionUnit.unitId,
  735. label: optionUnit.name
  736. })
  737. })
  738. }
  739. },
  740. // 食物信息标签切换
  741. foodInfoTabClick(tab) {
  742. },
  743. // 计算营养素摄入量
  744. calcNvIn() {
  745. this.calc.loading = true
  746. fPost(`/api/foods/${this.dlg.form.data.id}`, this.calc.req).then(res => {
  747. this.calc.rsp = res
  748. }).finally(() => {
  749. this.calc.loading = false
  750. })
  751. },
  752. // 计算单位转换
  753. calcCf() {
  754. this.cf.loading = true
  755. fPost(`/api/foods/${this.dlg.form.data.id}/unit-cf`, this.cf.req).then(res => {
  756. this.cf.rsp = res
  757. }).finally(() => {
  758. this.cf.loading = false
  759. })
  760. },
  761. // 刷新 CF
  762. refreshCf() {
  763. fGet(`/api/foods/${this.dlg.form.data.id}/cfs`).then(res => {
  764. this.dlg.form.data.cfs = res.map(v => {
  765. v._edit = false
  766. return v
  767. })
  768. })
  769. },
  770. // 保存 CF
  771. saveCf(cf) {
  772. fPost(`/api/foods/${this.dlg.form.data.id}/cfs`, cf).then(res => {
  773. this.refreshCf()
  774. })
  775. cf._edit = false
  776. },
  777. // 仅保存
  778. onlySave() {
  779. this.dlg.form.saveLoading = true
  780. fSave(this.URI, this.dlg.form.data).then(res => {
  781. this.$message.success('保存成功')
  782. this.refreshCf()
  783. }).finally(() => {
  784. this.dlg.form.saveLoading = false
  785. })
  786. }
  787. }
  788. }
  789. </script>