index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. <template>
  2. <div class="user">
  3. <div class="tree">
  4. <treeList
  5. title="产品分类"
  6. submitType="1"
  7. :data="treeListData"
  8. v-model="sourceList.pagination.productClassifyId"
  9. @change="treeChange"
  10. @changeTreeList="getTreeList"
  11. >
  12. </treeList>
  13. </div>
  14. <div class="content">
  15. <byTable
  16. :source="sourceList.data"
  17. :pagination="sourceList.pagination"
  18. :config="config"
  19. :loading="loading"
  20. highlight-current-row
  21. :selectConfig="selectConfig"
  22. :table-events="{
  23. //element talbe事件都能传
  24. select: select,
  25. }"
  26. :action-list="[
  27. props.selectStatus
  28. ? {}
  29. : {
  30. text: 'Excel导入',
  31. action: () => openExcel(),
  32. disabled: false,
  33. },
  34. props.selectStatus
  35. ? {}
  36. : {
  37. text: '添加',
  38. action: () => openModal('add'),
  39. disabled: false,
  40. },
  41. ]"
  42. @get-list="getList"
  43. >
  44. <template #pic="{ item }">
  45. <div v-if="item.fileList.length > 0">
  46. <img
  47. :src="item.fileList[0].fileUrl"
  48. class="pic"
  49. @click="handleClickFile(item.fileList[0])"
  50. />
  51. </div>
  52. <div v-else></div>
  53. </template>
  54. <template #size="{ item }">
  55. <div>
  56. <span>{{ item.productLong }}cm</span>*
  57. <span>{{ item.productWide }}cm</span>*
  58. <span>{{ item.productHigh }}cm</span>
  59. </div>
  60. </template>
  61. <template #price="{ item }">
  62. <div>
  63. <span v-if="item.price">{{ item.currency }} {{ item.price }}</span>
  64. </div>
  65. </template>
  66. <template #costPrice="{ item }">
  67. <div>
  68. <span v-if="item.costPrice"
  69. >{{ item.costCurrency }} {{ item.costPrice }}</span
  70. >
  71. </div>
  72. </template>
  73. </byTable>
  74. </div>
  75. <el-dialog
  76. :title="modalType == 'add' ? '添加产品' : '编辑产品'"
  77. v-model="dialogVisible"
  78. width="700"
  79. v-loading="submitLoading"
  80. destroy-on-close
  81. >
  82. <div class="public_height_dialog">
  83. <byForm
  84. :formConfig="formConfig"
  85. :formOption="formOption"
  86. v-model="formData.data"
  87. :rules="rules"
  88. ref="byform"
  89. >
  90. <template #nameEnglish>
  91. <div style="width: 100%">
  92. <el-form-item label="英文名" prop="nameEnglish">
  93. <el-input
  94. v-model="formData.data.nameEnglish"
  95. placeholder="请输入"
  96. onkeyup="value=value.replace(/[^\x00-\xff]/g, '')"
  97. ></el-input>
  98. <!-- @input="(val) => handleKeyup(val)" -->
  99. </el-form-item>
  100. </div>
  101. </template>
  102. <template #productPic>
  103. <div>
  104. <el-upload
  105. v-model:fileList="fileList"
  106. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  107. :data="uploadData"
  108. list-type="picture-card"
  109. :on-remove="handleRemove"
  110. :before-upload="handleBeforeUpload"
  111. accept=".gif, .jpeg, .jpg, .png"
  112. >
  113. <el-icon><Plus /></el-icon>
  114. </el-upload>
  115. </div>
  116. </template>
  117. </byForm>
  118. </div>
  119. <template #footer>
  120. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  121. <el-button
  122. type="primary"
  123. @click="submitForm('byform')"
  124. size="large"
  125. :loading="submitLoading"
  126. >确 定</el-button
  127. >
  128. </template>
  129. </el-dialog>
  130. <el-dialog
  131. title="导入产品"
  132. v-model="openExcelDialog"
  133. width="400"
  134. v-loading="excelLoading"
  135. >
  136. <el-upload
  137. :action="actionUrl + '/productInfo/excelImportByEhsd'"
  138. :headers="headers"
  139. :on-success="handleSuccess"
  140. :on-progress="handleProgress"
  141. :show-file-list="false"
  142. :on-error="handleError"
  143. accept=".xlsx"
  144. >
  145. <el-button type="primary">点击导入</el-button>
  146. </el-upload>
  147. <template #footer>
  148. <el-button @click="openExcelDialog = false" size="large"
  149. >取 消</el-button
  150. >
  151. </template>
  152. </el-dialog>
  153. </div>
  154. </template>
  155. <script setup>
  156. import { ElMessage, ElMessageBox } from "element-plus";
  157. import byTable from "@/components/byTable/index";
  158. import byForm from "@/components/byForm/index";
  159. import treeList from "@/components/product/treeList";
  160. import { getToken } from "@/utils/auth";
  161. const headers = ref({ Authorization: "Bearer " + getToken() });
  162. const actionUrl = import.meta.env.VITE_APP_BASE_API;
  163. const loading = ref(false);
  164. const submitLoading = ref(false);
  165. const treeListData = ref([]);
  166. const innerMethon = ref([]);
  167. const outsideMethon = ref([]);
  168. const productUnit = ref([]);
  169. const accountCurrency = ref([]);
  170. const sourceList = ref({
  171. data: [],
  172. pagination: {
  173. total: 3,
  174. pageNum: 1,
  175. pageSize: 10,
  176. type: "",
  177. productClassifyId: "",
  178. keyword: "",
  179. definition: "1",
  180. },
  181. });
  182. let dialogVisible = ref(false);
  183. let openExcelDialog = ref(false);
  184. let excelLoading = ref(false);
  185. let modalType = ref("add");
  186. let rules = ref({
  187. productClassifyId: [
  188. { required: true, message: "请选择产品分类", trigger: "change" },
  189. ],
  190. name: [{ required: true, message: "请输入产品名称", trigger: "blur" }],
  191. nameEnglish: [
  192. { required: true, message: "请输入产品英文名", trigger: "blur" },
  193. ],
  194. productLong: [
  195. { required: true, message: "请输入长 (cm)", trigger: "blur" },
  196. ],
  197. productWide: [
  198. { required: true, message: "请输入宽 (cm)", trigger: "blur" },
  199. ],
  200. productHigh: [
  201. { required: true, message: "请输入高 (cm)", trigger: "blur" },
  202. ],
  203. innerPackMethod: [
  204. { required: true, message: "请选择内包装方式", trigger: "change" },
  205. ],
  206. outerPackMethod: [
  207. { required: true, message: "请选择外包装方式", trigger: "change" },
  208. ],
  209. });
  210. const { proxy } = getCurrentInstance();
  211. const props = defineProps({
  212. selectStatus: Boolean,
  213. });
  214. const selectConfig = reactive([
  215. // {
  216. // label: "产品类型",
  217. // prop: "type",
  218. // data: [],
  219. // },
  220. ]);
  221. const config = computed(() => {
  222. return [
  223. {
  224. attrs: {
  225. label: "图片",
  226. slot: "pic",
  227. align: "center",
  228. width: 100,
  229. },
  230. },
  231. {
  232. attrs: {
  233. label: "产品编码",
  234. prop: "code",
  235. },
  236. },
  237. {
  238. attrs: {
  239. label: "产品名称",
  240. prop: "name",
  241. },
  242. },
  243. {
  244. attrs: {
  245. label: "尺寸",
  246. slot: "size",
  247. },
  248. },
  249. {
  250. attrs: {
  251. label: "销售指导价",
  252. slot: "price",
  253. width: 150,
  254. },
  255. },
  256. {
  257. attrs: {
  258. label: "成本价",
  259. slot: "costPrice",
  260. width: 150,
  261. },
  262. },
  263. {
  264. attrs: {
  265. label: "操作",
  266. width: "120",
  267. align: "center",
  268. },
  269. // 渲染 el-button,一般用在最后一列。
  270. renderHTML(row) {
  271. return [
  272. props.selectStatus
  273. ? {
  274. attrs: {
  275. label: "选择",
  276. type: "primary",
  277. text: true,
  278. },
  279. el: "button",
  280. click() {
  281. clickSelect(row);
  282. },
  283. }
  284. : {
  285. attrs: {
  286. label: "修改",
  287. type: "primary",
  288. text: true,
  289. },
  290. el: "button",
  291. click() {
  292. getDtl(row);
  293. },
  294. },
  295. props.selectStatus
  296. ? {}
  297. : {
  298. attrs: {
  299. label: "删除",
  300. type: "danger",
  301. text: true,
  302. },
  303. el: "button",
  304. click() {
  305. // 弹窗提示是否删除
  306. ElMessageBox.confirm(
  307. "此操作将永久删除该数据, 是否继续?",
  308. "提示",
  309. {
  310. confirmButtonText: "确定",
  311. cancelButtonText: "取消",
  312. type: "warning",
  313. }
  314. ).then(() => {
  315. // 删除
  316. proxy
  317. .post("/productInfo/delete", {
  318. id: row.id,
  319. })
  320. .then((res) => {
  321. ElMessage({
  322. message: "删除成功",
  323. type: "success",
  324. });
  325. getList();
  326. });
  327. });
  328. },
  329. },
  330. ];
  331. },
  332. },
  333. ];
  334. });
  335. const uploadData = ref({});
  336. const fileList = ref([]);
  337. const fileListCopy = ref([]);
  338. let formData = reactive({
  339. data: {},
  340. });
  341. const formOption = reactive({
  342. disabled: false,
  343. inline: true,
  344. labelWidth: 100,
  345. itemWidth: 100,
  346. rules: [],
  347. });
  348. const byform = ref(null);
  349. const formConfig = computed(() => {
  350. return [
  351. {
  352. type: "title",
  353. title: "基本信息",
  354. },
  355. {
  356. type: "treeSelect",
  357. prop: "productClassifyId",
  358. label: "产品分类",
  359. data: treeListData.value,
  360. itemWidth: 100,
  361. disabled: false,
  362. style: {
  363. width: "100%",
  364. },
  365. },
  366. {
  367. type: "input",
  368. prop: "name",
  369. label: "产品名称",
  370. itemWidth: 100,
  371. disabled: false,
  372. },
  373. {
  374. type: "slot",
  375. slotName: "nameEnglish",
  376. label: "",
  377. },
  378. {
  379. type: "slot",
  380. slotName: "productPic",
  381. prop: "fileList",
  382. label: "产品图片",
  383. },
  384. {
  385. type: "title",
  386. title: "价格信息",
  387. },
  388. {
  389. type: "selectInput",
  390. prop: "price",
  391. selectProp: "currency",
  392. label: "销售指导价",
  393. itemWidth: 50,
  394. style: {
  395. width: "100%",
  396. },
  397. data: accountCurrency.value,
  398. },
  399. {
  400. type: "selectInput",
  401. prop: "costPrice",
  402. selectProp: "costCurrency",
  403. label: "成本价",
  404. itemWidth: 50,
  405. style: {
  406. width: "100%",
  407. },
  408. data: accountCurrency.value,
  409. },
  410. {
  411. type: "title",
  412. title: "属性信息",
  413. },
  414. {
  415. type: "input",
  416. prop: "spec",
  417. label: "规格型号",
  418. itemWidth: 100,
  419. disabled: false,
  420. },
  421. {
  422. type: "input",
  423. prop: "productLong",
  424. label: "尺寸",
  425. itemWidth: 33.33,
  426. placeholder: "长(cm)",
  427. disabled: false,
  428. },
  429. {
  430. type: "input",
  431. prop: "productWide",
  432. label: " ",
  433. itemWidth: 33.33,
  434. placeholder: "宽(cm)",
  435. disabled: false,
  436. },
  437. {
  438. type: "input",
  439. prop: "productHigh",
  440. label: " ",
  441. itemWidth: 33.33,
  442. placeholder: "高(cm)",
  443. disabled: false,
  444. },
  445. {
  446. type: "select",
  447. prop: "innerPackMethod",
  448. label: "内包装方式",
  449. required: true,
  450. itemWidth: 50,
  451. multiple: true,
  452. data: innerMethon.value,
  453. filterable: true,
  454. placeholder: "内包装方式",
  455. style: {
  456. width: "100%",
  457. },
  458. disabled: false,
  459. },
  460. {
  461. type: "select",
  462. prop: "outerPackMethod",
  463. label: "外包装方式",
  464. required: true,
  465. itemWidth: 50,
  466. multiple: true,
  467. data: outsideMethon.value,
  468. filterable: true,
  469. placeholder: "外包装方式",
  470. style: {
  471. width: "100%",
  472. },
  473. disabled: false,
  474. },
  475. {
  476. type: "input",
  477. prop: "netWeight",
  478. label: "净重(kg)",
  479. itemWidth: 100,
  480. style: {
  481. width: "30%",
  482. },
  483. },
  484. {
  485. type: "input",
  486. prop: "hsCode",
  487. label: "海关编码",
  488. itemWidth: 100,
  489. style: {
  490. width: "30%",
  491. },
  492. disabled: false,
  493. },
  494. {
  495. type: "input",
  496. itemType: "textarea",
  497. prop: "remark",
  498. label: "备注",
  499. itemWidth: 100,
  500. },
  501. ];
  502. });
  503. const getList = async (req) => {
  504. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  505. loading.value = true;
  506. proxy
  507. .post("/productInfo/getConditionProductList", sourceList.value.pagination)
  508. .then(
  509. (message) => {
  510. sourceList.value.data = message.rows.map((x) => ({
  511. ...x,
  512. fileList: [],
  513. ...JSON.parse(x.ehsdJson),
  514. }));
  515. sourceList.value.pagination.total = message.total;
  516. setTimeout(() => {
  517. loading.value = false;
  518. }, 200);
  519. const productIdList = message.rows.map((x) => x.id);
  520. // 请求文件数据并回显
  521. if (productIdList.length > 0) {
  522. proxy
  523. .post("/fileInfo/getList", {
  524. businessIdList: productIdList,
  525. })
  526. .then((fileObj) => {
  527. for (let i = 0; i < sourceList.value.data.length; i++) {
  528. const e = sourceList.value.data[i];
  529. for (const key in fileObj) {
  530. if (e.id === key) {
  531. e.fileList = fileObj[key];
  532. }
  533. }
  534. }
  535. });
  536. }
  537. },
  538. (err) => {
  539. loading.value = false;
  540. }
  541. );
  542. };
  543. const treeChange = (e) => {
  544. sourceList.value.pagination.productClassifyId = e.id;
  545. getList({ productClassifyId: e.id });
  546. };
  547. const openModal = () => {
  548. dialogVisible.value = true;
  549. modalType.value = "add";
  550. formData.data = {
  551. definition: "1",
  552. outerPackMethod: [],
  553. innerPackMethod: [],
  554. fileList: [],
  555. fileListCopy: [],
  556. currency: "",
  557. costCurrency: "",
  558. };
  559. if (accountCurrency.value && accountCurrency.value.length > 0) {
  560. formData.data.currency = accountCurrency.value[0].value;
  561. formData.data.costCurrency = accountCurrency.value[0].value;
  562. }
  563. fileList.value = [];
  564. fileListCopy.value = [];
  565. };
  566. const openExcel = () => {
  567. openExcelDialog.value = true;
  568. };
  569. const needAtt = [
  570. "productClassifyId",
  571. "name",
  572. "spec",
  573. "remark",
  574. "fileList",
  575. "id",
  576. "unit",
  577. "definition",
  578. ];
  579. const submitForm = () => {
  580. byform.value.handleSubmit((valid) => {
  581. // if (!fileListCopy.value.length > 0) {
  582. // return ElMessage({
  583. // message: "请上传产品图片",
  584. // type: "info",
  585. // });
  586. // }
  587. let jsonObj = {};
  588. formData.data.fileList = fileListCopy.value.map((x) => ({
  589. id: x.id,
  590. fileName: x.fileName,
  591. }));
  592. for (const key in formData.data) {
  593. if (needAtt.includes(key)) {
  594. } else {
  595. jsonObj[key] = formData.data[key];
  596. delete formData.data[key];
  597. }
  598. }
  599. jsonObj.innerPackMethod = jsonObj.innerPackMethod.join(",");
  600. jsonObj.outerPackMethod = jsonObj.outerPackMethod.join(",");
  601. jsonObj.type = "1"; //1为公司产品库
  602. formData.data.ehsdJson = JSON.stringify(jsonObj);
  603. submitLoading.value = true;
  604. proxy.post(`/productInfo/${modalType.value}ByEhsd`, formData.data).then(
  605. (res) => {
  606. ElMessage({
  607. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  608. type: "success",
  609. });
  610. dialogVisible.value = false;
  611. submitLoading.value = false;
  612. getList();
  613. },
  614. (err) => {
  615. for (const key in jsonObj) {
  616. formData.data[key] = jsonObj[key];
  617. }
  618. formData.data.innerPackMethod =
  619. formData.data.innerPackMethod.split(",");
  620. formData.data.outerPackMethod =
  621. formData.data.outerPackMethod.split(",");
  622. submitLoading.value = false;
  623. }
  624. );
  625. });
  626. };
  627. const getTreeList = () => {
  628. proxy
  629. .post("/productClassify/tree", { parentId: "", name: "", definition: "1" })
  630. .then((message) => {
  631. treeListData.value = message;
  632. });
  633. };
  634. const getDtl = (row) => {
  635. modalType.value = "edit";
  636. proxy.post("/productInfo/detailByEhsd", { id: row.id }).then((res) => {
  637. res.definition = "1"; //产品
  638. let jsonObj = JSON.parse(res.ehsdJson);
  639. res = {
  640. ...res,
  641. currency: jsonObj.currency
  642. ? jsonObj.currency
  643. : accountCurrency.value[0].value,
  644. costCurrency: jsonObj.costCurrency
  645. ? jsonObj.costCurrency
  646. : accountCurrency.value[0].value,
  647. ...jsonObj,
  648. };
  649. if (res.innerPackMethod) {
  650. res.innerPackMethod = res.innerPackMethod.split(",");
  651. } else {
  652. res.innerPackMethod = [];
  653. }
  654. if (res.outerPackMethod) {
  655. res.outerPackMethod = res.outerPackMethod.split(",");
  656. } else {
  657. res.outerPackMethod = [];
  658. }
  659. formData.data = res;
  660. dialogVisible.value = true;
  661. proxy
  662. .post("/fileInfo/getList", { businessIdList: [row.id] })
  663. .then((fileObj) => {
  664. if (fileObj[row.id]) {
  665. fileList.value = fileObj[row.id].map((x) => ({
  666. ...x,
  667. url: x.fileUrl,
  668. }));
  669. fileListCopy.value = fileObj[row.id].map((x) => ({
  670. ...x,
  671. url: x.fileUrl,
  672. }));
  673. } else {
  674. fileList.value = [];
  675. fileListCopy.value = [];
  676. }
  677. });
  678. });
  679. };
  680. const isdisabled = ["price", "costPrice", "remark", "netWeight"];
  681. watch(modalType, (val) => {
  682. if (val) {
  683. for (let i = 0; i < formConfig.value.length; i++) {
  684. const element = formConfig.value[i];
  685. if (element.type != "title" || element.type != "slot") {
  686. if (!isdisabled.includes(element.prop)) {
  687. element.disabled = val == "edit" ? true : false;
  688. }
  689. }
  690. }
  691. }
  692. });
  693. const handleBeforeUpload = async (file) => {
  694. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  695. uploadData.value = res.uploadBody;
  696. fileListCopy.value.push({
  697. id: res.id,
  698. fileName: res.fileName,
  699. path: res.fileUrl,
  700. url: res.fileUrl,
  701. uid: file.uid,
  702. });
  703. };
  704. const handleRemove = (file) => {
  705. const index = fileListCopy.value.findIndex(
  706. (x) => x.uid === file.uid || x.id === file.id
  707. );
  708. fileListCopy.value.splice(index, 1);
  709. };
  710. const handleClickFile = (file) => {
  711. window.open(file.fileUrl, "_blank");
  712. };
  713. const handleProgress = () => {
  714. excelLoading.value = true;
  715. };
  716. const handleError = (err) => {
  717. ElMessage({
  718. message: `${err},请重试!`,
  719. type: "info",
  720. });
  721. openExcelDialog.value = false;
  722. excelLoading.value = false;
  723. };
  724. const handleSuccess = (res) => {
  725. if (res.code != 200) {
  726. return ElMessage({
  727. message: `${res.msg},请重试!`,
  728. type: "info",
  729. });
  730. } else {
  731. ElMessage({
  732. message: "导入成功!",
  733. type: "success",
  734. });
  735. openExcelDialog.value = false;
  736. excelLoading.value = false;
  737. getList();
  738. }
  739. };
  740. const getDict = () => {
  741. proxy
  742. .getDictOne([
  743. "inner_packaging_method_ehsd",
  744. "outside_packaging_method_ehsd",
  745. "unit",
  746. "account_currency",
  747. ])
  748. .then((res) => {
  749. innerMethon.value = res["inner_packaging_method_ehsd"].map((x) => ({
  750. label: x.dictValue,
  751. value: x.dictKey,
  752. }));
  753. outsideMethon.value = res["outside_packaging_method_ehsd"].map((x) => ({
  754. label: x.dictValue,
  755. value: x.dictKey,
  756. }));
  757. productUnit.value = res["unit"].map((x) => ({
  758. label: x.dictValue,
  759. value: x.dictKey,
  760. }));
  761. accountCurrency.value = res["account_currency"].map((x) => ({
  762. label: x.dictValue,
  763. value: x.dictKey,
  764. }));
  765. });
  766. };
  767. getDict();
  768. getTreeList();
  769. getList();
  770. const clickSelect = (item) => {
  771. proxy.$emit("selectProduct", item);
  772. };
  773. const handleKeypress = (event) => {
  774. // 判断输入字符是否为中文字符
  775. if (event.key.match(/[\u4e00-\u9fa5]/)) {
  776. // 阻止输入
  777. event.preventDefault();
  778. }
  779. };
  780. const handleKeyup = (val) => {
  781. // 过滤掉中文字符
  782. formData.data.nameEnglish = formData.data.nameEnglish.replace(
  783. /[\u4e00-\u9fa5]/g,
  784. ""
  785. );
  786. };
  787. </script>
  788. <style lang="scss" scoped>
  789. .user {
  790. padding: 20px;
  791. display: flex;
  792. justify-content: space-between;
  793. .tree {
  794. width: 300px;
  795. }
  796. .content {
  797. width: calc(100% - 320px);
  798. }
  799. }
  800. .pic {
  801. object-fit: contain;
  802. width: 50px;
  803. height: 50px;
  804. cursor: pointer;
  805. vertical-align: middle;
  806. }
  807. </style>