align-content align-items flex-direction flex-wrap flex-flow 什么意思

时间: 2023-08-18 11:49:14 AIGC 浏览: 239
这些词是CSS中Flexbox布局的属性。 - align-content:定义了多根轴线(即多行)的对齐方式,只有在有多行时才会生效。常用的取值有:flex-start、flex-end、center、space-between、space-around、stretch等。 - align-items:定义了单根轴线(即一行)上的对齐方式。常用的取值有:flex-start、flex-end、center、baseline、stretch等。 - flex-direction:定义了主轴的方向。常用的取值有:row(默认值,主轴为水平方向)、row-reverse(主轴水平方向,但是起点在右边)、column(主轴为垂直方向)、column-reverse(主轴垂直方向,但是起点在下方)。 - flex-wrap:定义了是否换行。常用的取值有:nowrap(默认值,不换行)、wrap(换行,第一行在上方)、wrap-reverse(换行,第一行在下方)。 - flex-flow:是flex-direction和flex-wrap的缩写,用于同时定义主轴方向和是否换行。常用的取值有:row nowrap(默认值,主轴为水平方向,不换行)、column wrap(主轴为垂直方向,换行)等。 这些属性一起使用可以控制Flexbox布局的方向、对齐方式和是否换行等。
相关问题

align-items flex-direction flex-wrap flex-flow

这四个属性都是用于控制flex布局的。 - align-items用于设置flex容器内的所有项目在交叉轴上的对齐方式。 - flex-direction用于设置主轴的方向。 - flex-wrap用于设置是否换行。 - flex-flow是flex-direction和flex-wrap两个属性的缩写。 希望我的回答可以帮助到你!

display: flex; height: 80rpx; padding: 8rpx; justify-content: flex-start; align-items: center; flex-flow: row; background: #f8f8f8;

### 使用效果 以下是对这段 CSS 代码 `display: flex; height: 80rpx; padding: 8rpx; justify-content: flex-start; align-items: center; flex-flow: row; background: #f8f8f8;` 各属性的使用效果分析: 1. **`display: flex`**:将元素设置为 Flex 容器,其内部子元素可以使用 Flex 布局的特性进行排列。 2. **`height: 80rpx`**:设置容器的高度为 80rpx,`rpx` 是小程序中的响应式像素单位,可根据屏幕宽度进行自适应。 3. **`padding: 8rpx`**:为容器的四个方向都添加 8rpx 的内边距,使内容与容器边界之间有一定的间隔。 4. **`justify-content: flex-start`**:子元素在主轴(这里是水平方向,因为 `flex-flow: row`)上从起始位置开始排列,即左对齐。 5. **`align-items: center`**:子元素在交叉轴(垂直方向)上居中对齐。 6. **`flex-flow: row`**:其是 `flex-direction` 和 `flex-wrap` 的缩写属性,这里表示子元素在水平方向上排列,且不换行。 7. **`background: #f8f8f8`**:设置容器的背景颜色为浅灰色。 以下是一个示例代码,展示其实际效果: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> .flex-container { display: flex; height: 80rpx; padding: 8rpx; justify-content: flex-start; align-items: center; flex-flow: row; background: #f8f8f8; } .flex-item { background-color: lightblue; padding: 5px; margin: 5px; } </style> </head> <body> <div class="flex-container"> <div class="flex-item">Item 1</div> <div class="flex-item">Item 2</div> <div class="flex-item">Item 3</div> </div> </body> </html> ``` ### 优化建议 1. **兼容性考虑**:如果需要兼容不支持 `rpx` 单位的环境,可以考虑使用 `px` 或 `rem` 等单位替代。 2. **代码可读性**:可以将 `flex-flow` 属性拆分为 `flex-direction` 和 `flex-wrap`,这样更便于理解和维护。例如: ```css .flex-container { display: flex; height: 80rpx; padding: 8rpx; justify-content: flex-start; align-items: center; flex-direction: row; flex-wrap: nowrap; background: #f8f8f8; } ``` 3. **响应式设计**:如果需要更好的响应式效果,可以结合媒体查询来调整容器的样式。例如: ```css @media (max-width: 768px) { .flex-container { height: auto; flex-direction: column; } } ```
阅读全文

相关推荐

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CINP Mechanism Research Hypothesis</title> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%); display: flex; flex-direction: column; align-items: center; padding: 20px; color: #2c3e50; } .container { max-width: 1200px; width: 100%; background: white; border-radius: 12px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); overflow: hidden; margin: 20px 0; } header { background: linear-gradient(90deg, #1a2980 0%, #26d0ce 100%); color: white; padding: 25px 40px; text-align: center; } h1 { margin: 0; font-size: 2.4rem; letter-spacing: 0.5px; font-weight: 600; } .subtitle { font-size: 1.1rem; opacity: 0.9; margin-top: 8px; font-weight: 300; } .content { padding: 30px; } .diagram-container { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 10px; padding: 25px; margin: 20px 0; min-height: 600px; display: flex; justify-content: center; align-items: center; } .mermaid { width: 100%; height: 550px; font-size: 14px; } .legend { display: flex; justify-content: center; gap: 25px; margin: 20px 0; flex-wrap: wrap; } .legend-item { display: flex; align-items: center; gap: 8px; } .legend-color { width: 20px; height: 20px; border-radius: 4px; } .key-mechanism { background-color: #e3f2fd; border-left: 4px solid #2196f3; padding: 20px; margin: 25px 0; border-radius: 0 8px 8px 0; } .key-mechanism h3 { margin-top: 0; color: #1a2980; } footer { text-align: center; padding: 20px; color: #7b8793; font-size: 0.9rem; border-top: 1px solid #e2e8f0; } @media (max-width: 768px) { .content { padding: 20px 15px; } h1 { font-size: 1.8rem; } .diagram-container { padding: 15px; min-height: 400px; } .mermaid { height: 380px; } } </style> </head> <body>
Chemotherapy-Induced Neuropathic Pain (CINP) Research Hypothesis Mechanism of Magnesium Sulfate Intervention in TNF-α→pNR2B-NMDA→Cellular Damage Pathway
Core Research Hypothesis Magnesium sulfate exerts pre-protective effects against CINP by dual-targeting the "TNF-α → pNR2B-NMDA receptor → cellular damage" signaling axis through: Inhibition of TNF-α via NF-κB pathway Antagonism of NMDA receptors via channel blockade Chemotherapy Input Key Pathological Processes MgSO₄ Intervention Neuroprotective Outcome flowchart TD %% Chemotherapy Input A[Chemotherapeutic Drugs]:::chemo --> B[CINP Development\nPeripheral/Central Sensitization\nGlial Cell Activation] %% Neuroinflammation-Excitotoxicity Cycle subgraph "Neuroinflammation-Excitotoxicity Cycle" B --> C[TNF-α Release] C --> D[TNF-α binds TNFR1] D --> E[Direct Sensitization of\nNociceptive Neurons] D --> F[Fyn Kinase Activation] F --> G[NR2B Phosphorylation\n(pTyr1472)] G --> H[Enhanced NMDA\nReceptor Function] H --> I[Excessive Glutamatergic\nSignaling] I --> J[Ca²⁺ Overload] J --> K[Neuronal Apoptosis &\nAutophagy Blockade] K --> L[Irreversible\nCellular Damage] L --> B end %% MgSO4 Intervention M[MgSO₄ Intervention]:::mgso4 --> N1[Inhibits TNF-α\nvia NF-κB pathway] N1 -.-> C M --> N2[Antagonizes NMDA Receptor\nvia Channel Blockade] N2 -.-> H %% Outcomes M --> O[Pre-protective Effect\nAgainst CINP]:::outcome O --> P[Reduced Neuronal Damage\nPain Alleviation]:::outcome %% Styling classDef chemo fill:#FFF9C4,stroke:#F57F17,stroke-width:2px classDef process fill:#FFCCBC,stroke:#E64A19,stroke-width:2px classDef mgso4 fill:#C8E6C9,stroke:#2E7D32,stroke-width:2px classDef outcome fill:#BBDEFB,stroke:#1565C0,stroke-width:2px class A chemo class B,C,D,E,F,G,H,I,J,K,L process class M,N1,N2 mgso4 class O,P outcome
Research Hypothesis Mechanism Diagram | CINP: Chemotherapy-Induced Neuropathic Pain
<script> mermaid.initialize({ startOnLoad: true, theme: 'default', fontFamily: 'Segoe UI, sans-serif', flowchart: { useMaxWidth: true, curve: 'basis', nodeSpacing: 50, rankSpacing: 70 }, securityLevel: 'loose' }); </script> </body> </html>

【单选题 】(10分)下面那个属性可以设置盒子的内边距 A. white-space B. margin C. width D. padding 2.【单选题 】(10分)请说出外边距定义规则的含义 margin : 5px 6px 10px; A. 定义的是上、左右、下边距的值 B. 定义的是上下、左、右边距的值 C. 定义的是上、右、下边距的值 D. 定义的是上、下、左右边距的值 3.【单选题 】(10分)下面哪个属性用来设置flex布局容器内容在交叉轴上的对齐方式: A. align-content B. flex-direction C. justify-content D. align-items 4.【单选题 】(10分)关于css的ID规则和class样式规则的命名,下面说法错误的是 A. 在给选择器命名时不能使用- B. 不建议使用字母序列abc,姓名拼音,或文字拼音缩写这样的命名方式; C. 在保证区块位置的情况下,可以使用结构化命名方式; D. 建议使用语义化的命名方式; 5.【单选题 】(10分)在使用flex布局时,如果需要项目换行,需要设置哪个属性: A. flex-wrap B. flex-flow C. flex-direction D. display 6.【多选题 】 (10分)下面哪些技巧可以优化css的定义和使用 A. 使用继承。 B. 使用外部样式表文件; C. 使用分组选择器; D. 使用简化属性; 7.【多选题 】 (10分)下面哪些是组合器选择器? A. a#menu:visited B. li#first + li C. div#header > a.style:hover D. div#top li 8.【多选题 】 (10分) 首页 要闻 一点号 下面哪个样式定义方案可以把上面的无序列表变成横向导航: A. ul#menu li{float: left;};ul#menu a{display: inline-block;} B. ul#menu{position: relative;};ul#menu li{position: absolute;};ul#menu a{display: inline-block;} C. ul#menu li,ul#menu a{display: inline-block;} D. ul#menu{display:flex;};ul#menu a{display: inline-block;} 9.【多选题 】 (10分)关于使用ID选择器和Class选择器,下面说法正确的是 A. Class选择器适用于跨功能区域、跨标签或没有特定规律的多次调用的样式定义。 B. 在定义时,ID选择器使用#作为样式开始,而Class选择器以.作为样式开始; C. ID选择器用于页面中特定功能区域的id命名,但必须是唯一的 D. 一个ID选择器在一个页面中可以多次调用,但是一个Class选择器在一个页面中只能使用一次 10.【多选题 】 (10分)下面哪些是默认的块元素: A. div B. span C. a D. ul

<template>
激励考核指下发 <a-button v-if="!readonly" type="link" icon="save" class="button_sd-webflow-button_webflow" @click="save" > 保存 </a-button> <a-button v-if="!readonly" type="link" icon="save" class="button_sd-webflow-button_webflow" @click="xfClick" > 下发 </a-button> <a-button type="link" icon="close-circle" class="button_sd-webflow-button_webflow" @click="btnClose" > 退出 </a-button>
激励考核指下发 <a-form-model ref="ruleForm" :rules="rules" :model="project" class="sitd-apply" layout="horizontal" > <label title="指标编号">指标编号</label> <a-form-model-item prop="zbbh"> <template>{{ project['zbbh'] }}</template> </a-form-model-item> <label title="指标年度" class="ant-form-item-required">指标年度</label> <a-form-model-item prop="zbnd"> <a-select v-if="!readonly" v-model="project['zbnd']" placeholder="请选择年份" style="width: 100%" > <a-select-option v-for="year in yearOptions" :key="year" :value="year"> {{ year }} </a-select-option> </a-select> <template v-else> {{ project['zbnd'] }} </template> </a-form-model-item> <label title="考核周期">考核周期</label> <a-form-model-item prop="khzq"> <a-input v-if="!readonly" v-model="project['khzq']" placeholder="考核周期" /> <template v-else>{{ project['khzq'] }}</template> </a-form-model-item> <label title="考核对象">考核对象</label> <a-form-model-item prop="khdx"> <a-select v-if="!readonly" v-model="selectedKhdxIds" mode="multiple" style="width: 100%" placeholder="请选择被考核对象" @change="handleKhdxChange" > <template v-for="(item, _i) in khdxList"> <a-select-option :key="item.code" :value="item.code">{{ item.value }}</a-select-option> </template> </a-select> <template v-else>{{ project['khdx'] }}</template> </a-form-model-item> <label title="创建日期" class="ant-form-item-required">创建日期</label> <a-form-model-item prop="cjrq"> <template>{{ project['cjrq'] ? refreshTime(project['cjrq']) : '' }}</template> </a-form-model-item> <label title="说明">说明</label> <a-form-model-item prop="sm"> <a-textarea v-model="project['sm']" placeholder="请输入内容" :max-length="300" class="m-textarea" :auto-size="{ minRows: 3, maxRows: 5 }" /> {{ ${project['sm']?.length || 0}/300 }} <template v-else>{{ project['sm'] }}</template> </a-form-model-item> </a-form-model> 激励考核指标 <a-button v-if="!readonly" type="primary" :style="{ marginLeft: '88px' }" class="button_sd-webflow-button_webflow" @click="openDialog" > 新增 </a-button> <a-button v-if="!readonly" :style="{ marginLeft: '8px' }" class="button_sd-webflow-button_webflow" :disabled="!selectedRowKeys.length" @click="btnBeforDelete" > 删除 </a-button> <SdTable ref="jlkhzbxf" row-key="id" :columns="jlkhzbxfColumns" :data-source.sync="jlkhzbxfResult" :loading="loading" :pagination="false" class="ant-table" bordered :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: btnSelectProject, }" > <template slot="指标内容" slot-scope="text, record, index"> {{ text }} </template> <template slot="分值" slot-scope="text, record, index"> {{ text }} </template> <template v-if="!readonly" slot="操作" slot-scope="text, record"> <a-button class="action-button" type="link" size="small" @click="btnOpenProjectDetails(record)" > 编辑 </a-button> </template> </SdTable> <a-modal title="激励考核指标" :visible="dialogVisible" width="35%" @ok="handleConfirm" @cancel="handleCancel" > <a-form-model ref="subFormRef" :rules="jlkhzbxfSubRules" :form="jlkhzbxfSubForm" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" > <a-row> <a-col :span="18"> <a-form-model-item label="指标类别"> <a-input v-model="jlkhzbxfSubForm['zblb']" allow-clear placeholder="请输入指标类别" /> </a-form-model-item> </a-col> </a-row> <a-row> <a-col :span="18"> <a-form-model-item label="指标内容"> <a-textarea v-model="jlkhzbxfSubForm['zbnr']" placeholder="请输入指标内容(按Enter换行)" :max-length="300" class="m-textarea" :auto-size="{ minRows: 3, maxRows: 6 }" /> </a-form-model-item> </a-col> </a-row> <a-row> <a-col :span="18"> <a-form-model-item label="分值"> <a-textarea v-model="jlkhzbxfSubForm['fz']" placeholder="请输入分值(按Enter换行)" :max-length="300" class="m-textarea" :auto-size="{ minRows: 2, maxRows: 4 }" /> </a-form-model-item> </a-col> </a-row> <a-row> <a-col :span="18"> <a-form-model-item label="分值上限"> <a-input v-model="jlkhzbxfSubForm['fzsx']" allow-clear placeholder='例如:"+1分"、"-1.5分"或"不设上限"' /> </a-form-model-item> </a-col> </a-row> </a-form-model> </a-modal>
</template> <script> import { Message, Modal } from 'ant-design-vue' import moment from 'moment' import components from './_import-components/zk-jlkh-zbxf-import' import KhypjService from './khypj-service' import crossWindowWatcher from '@/common/services/cross-window-watcher' import SdTable from '@/common/components/sd-table.vue' export default { name: 'ZkJlkhZbxf', metaInfo: { title: '激励考核指标下发', }, components: { ...components, SdTable, }, props: { id: { type: String, default: undefined, }, }, data() { // 添加校验规则 const validateFzsx = (rule, value, callback) => { if (!value) { callback() return } // 允许"不设上限" if (value === '不设上限') { callback() return } // 验证格式: ±数字(可含小数) + 单位(非数字字符) const regex = /^[+-]\d+(\.\d+)?[^\d]+$/ if (!regex.test(value)) { callback(new Error('格式错误,请填写"不设上限"或类似"+1分"、"-1.5分"的格式')) } else { callback() } } return { loading: false, ndkhLoading: false, dialogLoading: false, readonly: true, yearOptions: this.generateYearOptions(), rules: { zbnd: [{ required: true, message: '请选择指标年度', trigger: 'blur' }], }, jlkhzbxfSubRules: { fzsx: [{ validator: validateFzsx, trigger: 'blur' }], }, // 新增搜索表单数据 searchForm: { khnd: undefined, // 考核年度 khzq: undefined, // 考核周期 }, project: { id: undefined, // 主键id zbbh: undefined, // 指标编号 cjrq: undefined, // 创建日期 zbnd: undefined, // 指标年度 khzq: undefined, // 考核周期 khdx: undefined, // 考核对象 khdxId: undefined, // 考核对象id sm: undefined, // 说明 status: undefined, // 指标状态:0暂存,1下发(不可修改) ndkhId: undefined, // 关联的年度考核id }, jlkhzbxfResult: [], jlkhzbxfSubForm: { id: undefined, // id mainId: undefined, // 主表id zblb: undefined, // 指标类别 zbnr: undefined, // 指标内容 fz: undefined, // 分值 fzsx: undefined, // 分值上限 }, ndkhResult: [], khdxList: [], selectedKhdxIds: [], // 用于多选绑定的临时ID数组 dialogVisible: false, dialogVisibleGl: false, selectedKeys: [], selectedRows: [], selectedRowKeys: [], ndkhSelectedRowKeys: [], // 年度考核表格的选中项 ndkhSelectedRows: [], // 年度考核表格选中的行数据 selectedKeysAdd: [], selectedRowKeysAdd: [], // 年度考核表格的选中项 selectedRowsAdd: [], // 年度考核表格选中的行数据 isUpdateJlkhzbxfSub: false, isXf: false, ndkhColumns: [ { title: '考核编号', dataIndex: 'khbh', scopedSlots: { customRender: '考核编号', }, width: '200px', align: 'center', }, { title: '考核年度', dataIndex: 'khnd', scopedSlots: { customRender: '指标年度', }, width: '70px', align: 'center', }, { title: '考核对象', dataIndex: 'khdx', scopedSlots: { customRender: '责任主体', }, width: '200px', align: 'center', }, { title: '考核周期', dataIndex: 'khzq', scopedSlots: { customRender: '考核周期', }, width: '100px', align: 'center', }, ], dialogResult: [], dialogColumns: [], paginationOpt: { current: 1, // 当前页码 pageSize: 10, // 当前每页大小 total: 0, // 总数 showSizeChanger: true, showQuickJumper: false, pageSizeOptions: ['10', '20', '40', '60', '80', '100'], showTotal: (total) => 共 ${total} 条, onShowSizeChange: (current, pageSize) => { this.paginationOpt.current = 1 this.paginationOpt.pageSize = pageSize this.btnSearchBusinessList() }, onChange: (current, size) => { this.paginationOpt.current = current this.paginationOpt.pageSize = size this.btnSearchBusinessList() }, }, } }, computed: { // 动态计算列配置 jlkhzbxfColumns() { const baseColumns = [ { title: '序号', customRender: (text, record, index) => { return index + 1 }, align: 'center', width: '10%', }, { title: '指标类别', dataIndex: 'zblb', customRender: (text, record) => { // 只有显示行才渲染内容 if (record.rowSpan > 0) { return { children: text, attrs: { rowSpan: record.rowSpan }, } } return { attrs: { rowSpan: 0 } } }, align: 'center', width: '10%', }, { title: '指标内容', dataIndex: 'zbnr', scopedSlots: { customRender: '指标内容', }, align: 'center', width: '40%', }, { title: '分值', dataIndex: 'fz', scopedSlots: { customRender: '分值', }, align: 'center', width: '20%', }, { title: '分值上限', dataIndex: 'fzsx', scopedSlots: { customRender: '分值上限', }, align: 'center', width: '10%', }, ] // 非只读模式下添加操作列 if (!this.readonly) { baseColumns.push({ title: '操作', dataIndex: 'action', scopedSlots: { customRender: '操作' }, width: '10%', align: 'center', }) } return baseColumns }, }, watch: { jlkhzbxfResult: { handler(newVal) { this.calculateRowSpans(newVal) }, immediate: true, // 初始化时立即执行 deep: true, // 深度监听 }, }, created() { this.getKhdxList() this.jlkhzbxfResult = this.calculateRowSpans(this.jlkhzbxfResult) this.initJlkhzbxfInfo() }, mounted() { if (!this.$route.query.id) { this.project.zbbh = this.getZBbh() this.project.cjrq = moment(new Date()).format('YYYY-MM-DD') this.readonly = false } }, methods: { // 年度考核表格选中处理 btnSelectProjectNdkh(selectedRowKeys, selectedRows) { this.ndkhSelectedRowKeys = selectedRowKeys this.ndkhSelectedRows = [...selectedRows] }, btnSelectProjectAdd(selectedRowKeys, selectedRows) { this.selectedRowKeysAdd = selectedRowKeys this.selectedRowsAdd = [...selectedRows] }, // 重置搜索表单 reset() { this.searchForm = { khnd: undefined, // 考核年度 khzq: undefined, // 考核周期 } this.paginationOpt.current = 1 this.paginationOpt.pageSize = 10 this.btnSearchBusinessList() }, getKhzbxfInfo() { console.log('1111111----------', this.project) console.log('22222222----------', this.project.ndkhId) if (this.project.ndkhId) { KhypjService.getKhzbxfById(this.project.ndkhId).then((res) => { if (res.data.code === 200) { if (res.data.data) { this.ndkhResult.push(res.data.data) } else { this.ndkhResult = [] } } else { Message.error('获取考核指标下发信息失败!') } }) } }, ndkhBeforDelete() { const _this = this if (_this.ndkhSelectedRowKeys.length === 0) { Message.warning('请选择要删除的数据!') return } Modal.confirm({ content: '是否确认删除?', onOk() { _this.project.ndkhId = '-1' _this.saveJlkhzbxf() _this.ndkhResult = [] _this.ndkhSelectedRowKeys = [] // 清空选中状态 }, onCancel() {}, }) }, openDialogGl() { console.log('3333----------', this.ndkhResult) if (this.ndkhResult.length > 0) { Message.warning('只能关联一条年度考核!') return } this.dialogVisibleGl = true this.selectedKeysAdd = [] this.selectedRowsAdd = [] this.btnSearchBusinessList() }, handleDialogConfirm() { if (this.selectedRowsAdd.length === 0) { Message.warning('请选择一条年度考核!') return } if (this.selectedRowsAdd.length > 1) { Message.warning('只能关联一条年度考核!') return } this.project.ndkhId = this.selectedRowsAdd[0].id this.saveJlkhzbxf() this.getKhzbxfInfo() this.dialogVisibleGl = false }, btnSearchBusinessList() { this.dialogLoading = true const khzbxfSearchVo = { khnd: this.searchForm.khnd, khzq: this.searchForm.khzq, } const params = { current: this.paginationOpt.current, // 直接使用当前页码 pageSize: this.paginationOpt.pageSize, // 直接使用当前每页大小 searchVo: khzbxfSearchVo, } KhypjService.getNdkhList(params) .then((res) => { if (res.data.code === 200) { this.paginationOpt.total = res.data.data.total this.dialogResult = res.data.data.records } else { Message.error('查询失败!') } }) .catch((err) => { Message.error(err.message || err.data) this.paginationOpt.total = 0 this.dialogResult = [] }) .finally(() => { this.dialogLoading = false }) }, getKhdxList() { KhypjService.getCodeList('khdx').then((res) => { if (res.data.code === 200) { this.khdxList = res.data.data } else { Message.error('查询失败!') } }) }, // 处理考核对象选择变化 handleKhdxChange(selectedIds) { // 1. 拼接ID字符串 this.project.khdxId = selectedIds.join(';') // 2. 拼接名称字符串 const selectedNames = [] selectedIds.forEach((code) => { const item = this.khdxList.find((d) => d.code === code) if (item) { selectedNames.push(item.value) } }) this.project.khdx = selectedNames.join(';') }, btnBeforDelete() { const _this = this if (this.selectedRowKeys.length === 0) { Message.warning('请选择要删除的数据!') return } Modal.confirm({ content: '是否确认删除?', onOk() { _this.deleteJlkhzbxfSub() _this.selectedRowKeys = [] }, onCancel() {}, }) }, deleteJlkhzbxfSub() { KhypjService.removeJlkhzbxfSubByIds(this.selectedRowKeys).then((res) => { if (res.data.code === 200) { Message.success('删除成功!') this.getJlkhzbxfSubList() } else { Message.error('查询失败!') } }) }, btnSelectProject(selectedRowKeys, selectedRows) { this.selectedRowKeys = selectedRowKeys this.selectedRows = [...selectedRows] }, openDialog() { this.dialogVisible = true this.selectedKeys = [] this.selectedRows = [] this.jlkhzbxfSubForm = { id: undefined, // id mainId: this.$route.query.id, // 主表id zblb: undefined, // 指标类别 zbnr: undefined, // 指标内容 fz: undefined, // 分值 fzsx: undefined, // 分值上限 } // 新增子数据自动保存主数据 if (!this.$route.query.id) { this.saveJlkhzbxf() } }, btnOpenProjectDetails(record) { this.dialogVisible = true this.jlkhzbxfSubForm = { id: record.id, // id mainId: record.mainId, // 主表id zblb: record.zblb, // 指标类别 zbnr: record.zbnr, // 指标内容 fz: record.fz, // 分值 fzsx: record.fzsx, // 分值上限 } this.isUpdateJlkhzbxfSub = true console.log('121212------', record) console.log('33333222------', this.jlkhzbSubxfForm) }, handleCancel() { this.dialogVisible = false }, // 弹窗确认 handleConfirm() { // 添加表单校验 this.$refs.subFormRef.validate((valid) => { if (!valid) { return false } // 原有的保存逻辑... if (!this.isUpdateJlkhzbxfSub) { this.jlkhzbxfSubForm.mainId = this.$route.query.id // 保存子表数据 KhypjService.saveJlkhzbxfSub(this.jlkhzbxfSubForm).then((res) => { if (res.data.code === 200) { Message.success(添加成功!) this.getJlkhzbxfSubList() } else { Message.error('添加失败!') } }) } else { // 保存子表数据 KhypjService.updateJlkhzbxfSub(this.jlkhzbxfSubForm).then((res) => { if (res.data.code === 200) { Message.success(修改成功!) this.getJlkhzbxfSubList() } else { Message.error('修改失败!') } }) this.isUpdateJlkhzbxfSub = false } this.dialogVisible = false }) }, // handleConfirm() { // if (!this.isUpdateJlkhzbxfSub) { // this.jlkhzbxfSubForm.mainId = this.$route.query.id // // 保存子表数据 // KhypjService.saveJlkhzbxfSub(this.jlkhzbxfSubForm).then((res) => { // if (res.data.code === 200) { // Message.success(添加成功!) // this.getJlkhzbxfSubList() // } else { // Message.error('添加失败!') // } // }) // } else { // // 保存子表数据 // KhypjService.updateJlkhzbxfSub(this.jlkhzbxfSubForm).then((res) => { // if (res.data.code === 200) { // Message.success(修改成功!) // this.getJlkhzbxfSubList() // } else { // Message.error('修改失败!') // } // }) // this.isUpdateJlkhzbxfSub = false // } // this.dialogVisible = false // }, // 计算行合并 calculateRowSpans(data) { if (!data || data.length === 0) return data const categoryMap = {} // 第一步:统计每个类别的行数 data.forEach((item) => { categoryMap[item.zblb] = (categoryMap[item.zblb] || 0) + 1 }) // 第二步:设置行合并属性 let lastCategory = null return data.map((item) => { // 重置rowSpan属性 item.rowSpan = undefined if (item.zblb !== lastCategory) { lastCategory = item.zblb // 只有每个类别的第一行设置rowSpan item.rowSpan = categoryMap[item.zblb] return item } // 同类别的后续行设置rowSpan为0 item.rowSpan = 0 return item }) }, // 生成年份选项 generateYearOptions() { const currentYear = new Date().getFullYear() const years = [] // 添加年份:当前年后1年、本年、前1年、前2年 years.push(currentYear + 1) // 后1年 years.push(currentYear) // 本年 years.push(currentYear - 1) // 前1年 years.push(currentYear - 2) // 前2年 return years }, btnClose() { window.close() }, initJlkhzbxfInfo() { if (this.$route.query.id) { KhypjService.getJlkhzbxfById(this.$route.query.id).then((res) => { if (res.data.code === 200) { this.project = res.data.data this.project.cjrq = this.project.cjrq ? moment(new Date(this.project.cjrq)).format('YYYY-MM-DD') : null this.readonly = this.project.status === 1 // 初始化选中项 if (this.project.khdxId) { this.selectedKhdxIds = this.project.khdxId.split(';').filter(Boolean) } this.getJlkhzbxfSubList() this.getKhzbxfInfo() } else { Message.error('获取考核指标库信息失败!') } }) } }, save() { const _this = this this.$refs.ruleForm.validate((valid, obj) => { if (!valid) { Message.warning('请输入必填项!') return false } else { _this.saveJlkhzbxf() } }) }, xfClick() { this.readonly = true this.isXf = true this.save() KhypjService.jlkhzbzpXfStart(this.$route.query.id).then((res) => { if (res.data.code === 200) { Message.success('下发成功!') } else { Message.error('下发失败!') } }) }, // 修改 saveJlkhzbxf 方法返回 Promise saveJlkhzbxf() { const _this = this if (this.isXf) { this.project.status = 1 } else { this.project.status = 0 } // 创建数据副本,避免污染原始数据 const postData = { ...this.project } // 仅在值是字符串时才进行转换 if (postData.cjrq && typeof postData.cjrq === 'string') { postData.cjrq = this.strToTimestamp(postData.cjrq) } // 返回一个 Promise return new Promise((resolve, reject) => { // 判断是新增还是更新 const apiCall = !this.$route.query.id ? KhypjService.saveJlkhzbxf(postData) : KhypjService.updateJlkhzbxf(postData) apiCall .then((res) => { if (res.data.code === 200) { // 处理新增保存成功 if (!_this.$route.query.id) { Message.success('保存成功!') if (res.data.data) { const currentUrl = window.location.href const newUrl = currentUrl.replace('zbxf', zbxf?id=${res.data.data}) // 直接跳转页面,不需要等待初始化 window.location.href = newUrl } resolve() // 解析 Promise } // 处理更新保存成功 else { if (_this.project.status === 1) { Message.success('提交成功!') } else { Message.success('保存成功!') } resolve() // 解析 Promise } } else { // 处理失败情况 const errorMessage = !_this.project.id ? '保存失败!' : _this.project.status === 1 ? '提交失败!' : '保存失败!' Message.error(errorMessage) reject(new Error(res.data.message || errorMessage)) } }) .catch((error) => { // 处理 API 错误 const errorMessage = !_this.project.id ? '保存失败!' : _this.project.status === 1 ? '提交失败!' : '保存失败!' console.error('API 错误:', error) Message.error(errorMessage) reject(error) }) }) }, getJlkhzbxfSubList() { KhypjService.getJlkhzbxfSubList(this.$route.query.id).then((res) => { if (res.data.code === 200) { this.jlkhzbxfResult = res.data.data } else { Message.error('获取子表信息失败!') } }) }, // 获取唯一指标编号 getZBbh() { // 获取当前时间 const now = new Date() // 获取当前时间的年、月、日、时、分、秒、毫秒 const year = now.getFullYear() const month = String(now.getMonth() + 1).padStart(2, '0') const day = String(now.getDate()).padStart(2, '0') const hour = String(now.getHours()).padStart(2, '0') const minute = String(now.getMinutes()).padStart(2, '0') const second = String(now.getSeconds()).padStart(2, '0') const millisecond = String(now.getMilliseconds()).padStart(3, '0') // 生成唯一标识 const uniqueId = ${year}${month}${day}${hour}${minute}${second}${millisecond} return 'JLKHZBXF-' + uniqueId }, strToTimestamp(dateStr) { const date = moment(dateStr, 'YYYY-MM-DD') return date.valueOf() }, refreshTime(item) { return moment(item).format('YYYY-MM-DD') }, }, } </script> <style lang="scss" scoped> /* 设置表格宽度 */ .ant-table { width: 90%; margin: auto; /* 居中显示 */ } .sitd-collapse-block { width: 90%; margin: auto; &::v-deep(.ant-collapse-content-box) { padding: unset !important; } } table { width: 90%; margin: auto; border-top: 1px solid #e8e8e8; margin-bottom: 16px; table-layout: fixed; tr td { border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; min-height: 100px; &:first-child { border-left: unset; } &:nth-child(2n + 1) { background: #fafafa; width: 170px; } &.upload-td { background: #fafafa; width: 170px !important; } &.upload-time-td { background: #fafafa; width: 200px !important; } &.ant-form-item-check { width: 194px !important; } .ant-form-item { margin-bottom: unset !important; padding: 5px; .ant-form-item-label { width: 170px; padding-bottom: 1px; text-align: center; background-color: #fafafa; } } &::v-deep(label) { display: block; margin: 0 auto; text-align: right; white-space: normal; line-height: 20px; padding: 0 5px; } .ant-form-item-prompt { display: block; margin: 0 auto; text-align: right; white-space: normal; line-height: 20px; padding: 0 14px 0 5px; font-size: 16px; color: rgba(0, 0, 0, 0.85); } .prompt-red { color: #f5222d !important; } .ant-form-item-radio { &::v-deep(label) { display: inline !important; } } &::v-deep(.ant-checkbox + span) { padding-right: 0 !important; } } ::v-deep(.ant-form-item-control-wrapper) { min-height: 40px; } } .ant-form-long-label { tr td { &:nth-child(2n + 1) { // width: 200px !important; } } } .ant-collapse { border-top: 1px solid #d9d9d9; border-bottom: unset; border-left: unset; border-right: unset; width: 90%; margin: auto; & > .ant-collapse-item { border-bottom: unset; /*& > .ant-collapse-content{*/ /* border-top: 1px solid #d9d9d9;*/ /* border-bottom: 1px solid #d9d9d9;*/ /* border-radius: 4px;*/ /*}*/ &::v-deep(.ant-collapse-content) { border-top: unset; } } } .textarea-wrapper { position: relative; display: block; .m-textarea { padding: 8px 12px; height: 100%; } .m-count { color: #808080; background: #fff; position: absolute; font-size: 12px; bottom: 12px; right: 12px; line-height: 16px; } } .ant-spin-loading { width: 100vw; height: 100vh; display: block; background-color: rgba(0, 0, 0, 0.5); position: fixed; top: 0; left: 0; z-index: 99; } .apply-block { display: flex; align-items: center; .dynamic-delete-button { cursor: pointer; position: relative; font-size: 24px; color: #999; transition: all 0.3s; } .dynamic-delete-button:hover { color: #777; } .dynamic-delete-button[disabled] { cursor: not-allowed; opacity: 0.5; } div { flex: 1; } } .btn-group { display: flex; align-items: center; justify-content: right; width: 90%; margin: 0 auto 20px; button { margin-left: 10px; } } .ant-form-budget-border { border-bottom: 1px solid #d9d9d9; margin-left: -1px; } .budget-box { height: 100%; overflow: hidden; display: flex; flex: 1; flex-direction: column; } .budget-record { width: 100%; height: 100%; overflow: auto; display: flex; justify-content: center; background: #fff; } .budget-record-table { width: 90%; //调整页面表格宽度 // min-width: 840px; padding: 16px; } .budget-record-table-title { margin-bottom: 20px; text-align: center; white-space: pre-wrap; } .header_sd-header_common.ant-layout-header { padding: 0 20px 0 20px; color: #fff; background-image: linear-gradient(90deg, #1890ff 0%, #0162eb 100%); height: 64px; line-height: 64px; } .header_sd-header_common { z-index: 1; } .ant-layout-header { background: #001529; } .ant-layout-header, .ant-layout-footer { flex: 0 0 auto; } header { display: block; } .ant-layout, .ant-layout * { box-sizing: border-box; } .left_sd-header_common { float: left; height: 100%; } .right_sd-header_common { float: right; height: 100%; } .logo_sd-webflow_webflow h3 { color: #fff; } .header_sd-header_common .ant-btn-link { color: #fff; } .button_sd-webflow-button_webflow { max-width: 100%; } </style> 检查代码,针对分值上限设置的校验规则并未生效,请检查代码并修改

Cart.php <?php /** * Custom Cart Page for WooCommerce with Selective Checkout * RECOMMENDED LOCATION (Woo override): * /wp-content/themes/your-child-theme/woocommerce/cart/cart.php * ALTERNATIVE (if your site is wired this way): * /wp-content/themes/woodmart-child/cart.php */ if (!defined('ABSPATH')) { exit; } do_action('woocommerce_before_cart'); // Provide tiny context for JS (invisible; no layout change) $pc_cart_is_empty = WC()->cart->is_empty(); function pc_uid_for_view() { if (is_user_logged_in()) return 'user_' . get_current_user_id(); if (empty($_COOKIE['pc_cart_uid'])) { $token = wp_generate_uuid4(); setcookie('pc_cart_uid', $token, time() + YEAR_IN_SECONDS, COOKIEPATH ?: '/', '', is_ssl(), false); $_COOKIE['pc_cart_uid'] = $token; } return 'guest_' . sanitize_text_field(wp_unslash($_COOKIE['pc_cart_uid'])); } $pc_uid = pc_uid_for_view(); ?> <form class="woocommerce-cart-form" action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post"> <?php do_action('woocommerce_before_cart_table'); ?> <?php wp_nonce_field('woocommerce-cart', 'woocommerce-cart-nonce'); ?> <input type="checkbox" id="select-all-items" /> <label for="select-all-items" style="display: inline-block; margin-left: 5px; cursor: pointer;">全选</label> <?php esc_html_e('Product', 'woocommerce'); ?> <?php esc_html_e('Price', 'woocommerce'); ?> <?php esc_html_e('Quantity', 'woocommerce'); ?> <?php esc_html_e('Subtotal', 'woocommerce'); ?> <?php esc_html_e('操作', 'woocommerce'); ?> <?php do_action('woocommerce_before_cart_contents'); ?> <?php foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) : ?> <?php $_product = apply_filters('woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key); $product_id = apply_filters('woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key); if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters('woocommerce_cart_item_visible', true, $cart_item, $cart_item_key) ) : $product_permalink = apply_filters('woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink($cart_item) : '', $cart_item, $cart_item_key); $line_total_value = (float) ($cart_item['line_total'] + $cart_item['line_tax']); $variation_id = isset($cart_item['variation_id']) ? (int)$cart_item['variation_id'] : 0; $variation_data = isset($cart_item['variation']) ? $cart_item['variation'] : array(); $variation_json = wp_json_encode($variation_data); ?> <input type="checkbox" class="item-checkbox" name="selected_items[]" value="<?php echo esc_attr($cart_item_key); ?>" data-price="<?php echo esc_attr($line_total_value); ?>" /> <?php $thumbnail = apply_filters('woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key); if ( ! $product_permalink ) : echo $thumbnail; // PHPCS: XSS ok. else : printf('%s', esc_url($product_permalink), $thumbnail); // PHPCS: XSS ok. endif; ?> <?php if ( ! $product_permalink ) : echo wp_kses_post( apply_filters('woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key) . ' ' ); else : echo wp_kses_post( apply_filters('woocommerce_cart_item_name', sprintf('%s', esc_url($product_permalink), $_product->get_name()), $cart_item, $cart_item_key) ); endif; do_action('woocommerce_after_cart_item_name', $cart_item, $cart_item_key); echo wc_get_formatted_cart_item_data($cart_item); // PHPCS: XSS ok. ?> <?php echo apply_filters('woocommerce_cart_item_price', WC()->cart->get_product_price($_product), $cart_item, $cart_item_key); // PHPCS: XSS ok. ?> <?php if ( $_product->is_sold_individually() ) : $product_quantity = sprintf('1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key); else : $product_quantity = woocommerce_quantity_input( array( 'input_name' => "cart[{$cart_item_key}][qty]", 'input_value' => $cart_item['quantity'], 'max_value' => $_product->get_max_purchase_quantity(), 'min_value' => '0', 'product_name' => $_product->get_name(), ), $_product, false ); endif; echo apply_filters('woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item); // PHPCS: XSS ok. ?> 保存中… <?php echo apply_filters('woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal($_product, $cart_item['quantity']), $cart_item, $cart_item_key); // PHPCS: XSS ok. ?> <?php echo apply_filters('woocommerce_cart_item_remove_link', sprintf( '×', esc_url( wc_get_cart_remove_url($cart_item_key) ), esc_attr__('Remove this item', 'woocommerce'), esc_attr($product_id), esc_attr($_product->get_sku()) ), $cart_item_key); ?> <?php endif; ?> <?php endforeach; ?> <?php do_action('woocommerce_after_cart_contents'); ?> <?php do_action('woocommerce_after_cart_table'); ?> </form> <input type="checkbox" id="footer-select-all"> <label for="footer-select-all" style="display: inline-block; margin-left: 5px; cursor: pointer;">全选</label> <button type="button" class="button" id="remove-selected-items">刪除選中的商品</button> <button type="button" class="button" id="clear-cart">清空購物車</button> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="输入优惠券代码" style="padding: 8px; width: 200px; border: 1px solid #ddd; border-radius: 4px; margin-right: 5px;" /> <button type="button" class="button" id="apply-coupon">应用优惠券</button> 已选商品: 0 件,共计: RM0.00 结算 <?php do_action('woocommerce_after_cart'); ?> <style> /* Your original styles exactly untouched */ <?php /* Keeping exactly your CSS content */ ?> .cart-page-section { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); margin-bottom: 30px; } .cart-page-section table.cart { width: 100%; border-collapse: collapse; margin-bottom: 20px; } .cart-page-section table.cart th, .cart-page-section table.cart td { padding: 15px; text-align: left; border-bottom: 1px solid #eee; } .cart-page-section table.cart th { background-color: #f8f8f8; font-weight: bold; } .cart-page-section table.cart th.product-select, .cart-page-section table.cart td.product-select { width: 8%; text-align: center; vertical-align: middle; white-space: nowrap; } .cart-page-section table.cart td.product-info { width: 37%; vertical-align: top; } .cart-page-section table.cart .product-info .product-image { float: left; margin-right: 15px; width: 100px; height: 100px; } .cart-page-section table.cart .product-info .product-image img { max-width: 100%; height: auto; display: block; } .cart-page-section table.cart .product-info .product-name { overflow: hidden; } .cart-page-section table.cart td.product-price, .cart-page-section table.cart td.product-quantity, .cart-page-section table.cart td.product-subtotal { width: 15%; vertical-align: middle; } .cart-page-section table.cart td.product-remove { width: 5%; text-align: center; vertical-align: middle; } .cart-footer-actions { position: sticky; bottom: 0; background: #fff; padding: 15px; border-top: 1px solid #ddd; box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); z-index: 1000; display: flex; flex-direction: column; gap: 15px; } .footer-left { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; } .coupon-section { display: flex; align-items: center; gap: 5px; } .selected-summary { font-size: 16px; font-weight: bold; flex: 1; } .cart-footer-actions .button { padding: 10px 20px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background-color 0.3s; white-space: nowrap; } .cart-footer-actions .button:hover { background-color: #d32f2f; } #partial-checkout { padding: 12px 24px; background-color: #2196F3; color: white; text-decoration: none; border-radius: 4px; display: inline-block; transition: background-color 0.3s; white-space: nowrap; text-align: center; font-weight: bold; } #partial-checkout:hover { background-color: #0b7dda; } #coupon_code { padding: 8px; width: 200px; border: 1px solid #ddd; border-radius: 4px; transition: border-color 0.3s; } #coupon_code:focus { border-color: #2196F3; outline: none; } @media (max-width: 768px) { .cart-page-section table.cart thead { display: none; } .cart-page-section table.cart td { display: block; width: 100% !important; text-align: right; padding: 10px; position: relative; padding-left: 50%; } .cart-page-section table.cart td::before { content: attr(data-title); position: absolute; left: 15px; font-weight: bold; text-align: left; } .cart-page-section table.cart .product-info .product-image { float: none; margin: 0 auto 10px; } .cart-page-section table.cart td.product-select::before { content: "选择"; } .cart-footer-actions { flex-direction: column; align-items: flex-start; } .footer-left { width: 100%; justify-content: space-between; } .coupon-section { width: 100%; margin-top: 10px; } .coupon-section input { flex: 1; } .cart-footer-actions .footer-bottom-row { flex-direction: column; align-items: stretch; } .selected-summary { text-align: center; margin-bottom: 10px; } #partial-checkout { width: 100%; padding: 15px; } .cart-footer-actions .button { padding: 12px 15px; margin: 5px 0; width: 100%; text-align: center; } } @media (max-width: 480px) { .cart-page-section { padding: 15px; } .cart-page-section table.cart td { padding-left: 45%; } .cart-page-section table.cart td::before { font-size: 14px; } .cart-footer-actions { padding: 10px; } #coupon_code { width: 100%; } } <style> /* 添加加载动画样式 */ .quantity-saving-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); display: flex; align-items: center; justify-content: center; z-index: 10; border-radius: 4px; } .quantity-saving-loader { width: 24px; height: 24px; border: 3px solid #f3f3f3; border-top: 3px solid #3498db; border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* 使数量输入框容器相对定位 */ .product-quantity .quantity { position: relative; } </style> <script> jQuery(function($){ // Context var PC = { ajax_url: (window.wc_cart_params && window.wc_cart_params.ajax_url) || '<?php echo esc_url( admin_url("admin-ajax.php") ); ?>', security: (function(){ var n = $('input[name="woocommerce-cart-nonce"]').val(); if (n) return n; if (window.wc_cart_params && window.wc_cart_params.cart_nonce) return window.wc_cart_params.cart_nonce; return '<?php echo wp_create_nonce("woocommerce-cart"); ?>'; })(), cart_is_empty: <?php echo $pc_cart_is_empty ? 'true' : 'false'; ?>, cart_uid: '<?php echo esc_js($pc_uid); ?>' }; // Keys function lsKey(name){ return 'pc_' + name + '_' + PC.cart_uid; } var LS_SELECTION = lsKey('selected_items'); var LS_MASTER = lsKey('cart_master'); // Utilities function getSelectedKeys(){ return $('.item-checkbox:checked').map(function(){ return this.value; }).get(); } function fmtRM(n){ n = isNaN(n) ? 0 : n; return 'RM' + Number(n).toFixed(2); } // Selection persistence function readSelection(){ try { return JSON.parse(localStorage.getItem(LS_SELECTION) || '[]'); } catch(e){ return []; } } function writeSelection(keys){ try { localStorage.setItem(LS_SELECTION, JSON.stringify(keys||[])); } catch(e){} } function restoreSelectionFromLS(){ var saved = readSelection(); if (!Array.isArray(saved)) saved = []; $('.item-checkbox').each(function(){ $(this).prop('checked', saved.indexOf(this.value) !== -1); }); } window.addEventListener('storage', function(ev){ if (ev.key === LS_SELECTION) { restoreSelectionFromLS(); updateSelectedSummary(); } }); // Selected summary function updateSelectedSummary(){ var total = 0, count = 0; $('.item-checkbox:checked').each(function(){ var price = parseFloat($(this).data('price')); if (!isNaN(price)) { total += price; count++; } }); $('#selected-count').text(count); $('#selected-total').text(fmtRM(total)); var totalCbs = $('.item-checkbox').length; var checkedCbs = $('.item-checkbox:checked').length; var allChecked = totalCbs > 0 && checkedCbs === totalCbs; $('#select-all-items, #footer-select-all').prop('checked', allChecked); writeSelection(getSelectedKeys()); } // Select all $('#select-all-items, #footer-select-all').off('change.sc').on('change.sc', function(){ var checked = $(this).prop('checked'); $('.item-checkbox').prop('checked', checked); updateSelectedSummary(); }); $(document).on('change', '.item-checkbox', updateSelectedSummary); // Snapshot cart DOM -> localStorage (guest resilience) function snapshotCartFromDOM() { var items = []; $('tr.cart_item').each(function(){ var $row = $(this); var pid = parseInt($row.attr('data-product_id'),10)||0; var vid = parseInt($row.attr('data-variation_id'),10)||0; var qty = parseFloat($row.find('input.qty').val())||0; var variation = {}; try { variation = JSON.parse($row.attr('data-variation')||'{}'); } catch(e){ variation = {}; } if (pid && qty > 0) { items.push({ product_id: pid, variation_id: vid, variation: variation, quantity: qty }); } }); try { localStorage.setItem(LS_MASTER, JSON.stringify({ ts: Date.now(), items: items })); } catch(e){} } function maybeRehydrateFromLocal() { if (!PC.cart_is_empty) return; var raw = localStorage.getItem(LS_MASTER); if (!raw) return; var data; try { data = JSON.parse(raw); } catch(e){ return; } var items = (data && data.items) ? data.items : []; if (!items.length) return; $.ajax({ url: PC.ajax_url, method: 'POST', dataType: 'json', data: { action: 'pc_rehydrate_cart', security: PC.security, items: JSON.stringify(items) } }).done(function(res){ if (res && res.success) { // The current page is cart; reload to display rehydrated items location.reload(); } }); } // Remove selected $('#remove-selected-items').off('click.sc').on('click.sc', function(){ var keys = getSelectedKeys(); if (!keys.length) { alert('请选择要删除的商品'); return; } if (!confirm('确定要删除选中的商品吗?')) return; $.ajax({ url: PC.ajax_url, method: 'POST', dataType: 'json', data: { action: 'remove_selected_cart_items', selected_items: keys, security: PC.security } }).done(function(res){ if (res && res.success) { var saved = readSelection().filter(function(k){ return keys.indexOf(k) === -1; }); writeSelection(saved); location.reload(); } else { alert((res && res.data && (res.data.message || res.data)) || '删除失败,请重试'); } }).fail(function(){ alert('删除失败,请重试'); }); }); // Clear cart $('#clear-cart').off('click.sc').on('click.sc', function(){ if (!confirm('确定要清空购物车吗?')) return; $.ajax({ url: PC.ajax_url, method: 'POST', dataType: 'json', data: { action: 'empty_cart', security: PC.security } }).done(function(res){ if (res && res.success) { writeSelection([]); localStorage.removeItem(LS_MASTER); location.reload(); } else { alert((res && res.data && (res.data.message || res.data)) || '清空购物车失败,请重试'); } }).fail(function(){ alert('清空购物车失败,请重试'); }); }); // Apply coupon $('#apply-coupon').off('click.sc').on('click.sc', function(){ var code = ($.trim($('#coupon_code').val()) || ''); if (!code) { alert('请输入优惠券代码'); return; } var $btn = $(this).prop('disabled', true).text('处理中...'); $.ajax({ url: PC.ajax_url, method: 'POST', dataType: 'json', data: { action: 'apply_coupon', coupon_code: code, security: PC.security } }).done(function(res){ if (res && res.success) { location.reload(); } else { alert((res && res.data && (res.data.message || res.data)) || '优惠券应用失败,请重试'); $btn.prop('disabled', false).text('应用优惠券'); } }).fail(function(){ alert('发生错误,请重试'); $btn.prop('disabled', false).text('应用优惠券'); }); }); // Quantity auto-save (per-row only; no page hold) // 修复后的数量自动保存功能 function parseCartKeyFromInputName(n){ // 修正的正则表达式 - 匹配: cart[<cart_item_key>][qty] var m = (n||'').match(/^cart\[(.+?)\]\[qty\]$/); return m ? m[1] : null; } // 创建加载动画元素 function createLoader() { var $overlay = $(''); return $overlay; } // Quantity auto-save with loader effect function parseCartKeyFromInputName(n){ // 修正正则表达式 var m = (n||'').match(/^cart\[(.+?)\]\[qty\]$/); return m ? m[1] : null; } var qtyTimers = {}; $(document).on('input change', '.qty', function(){ var $input = $(this); var key = parseCartKeyFromInputName($input.attr('name')); if (!key) return; var row = $input.closest('tr'); var $quantityContainer = $input.closest('.quantity'); var val = parseInt($input.val(), 10); if (isNaN(val) || val < 0) val = 0; // 清除现有定时器 if (qtyTimers[key]) clearTimeout(qtyTimers[key]); // 创建加载动画容器(如果不存在) if (!$quantityContainer.find('.quantity-saving-overlay').length) { $quantityContainer.append(createLoader()); } // 隐藏加载层 $quantityContainer.find('.quantity-saving-overlay').hide(); // 设置新的定时器 qtyTimers[key] = setTimeout(function(){ // 显示加载动画 $quantityContainer.find('.quantity-saving-overlay').show(); $input.prop('disabled', true); $.ajax({ url: PC.ajax_url, method: 'POST', dataType: 'json', data: { action: 'update_cart_item_qty', cart_item_key: key, qty: val, security: PC.security } }).done(function(res){ if (res && res.success && res.data){ if (res.data.subtotal_html) { row.find('td.product-subtotal').html(res.data.subtotal_html); } // 更新复选框价格 var $cb = row.find('.item-checkbox'); if ($cb.length && typeof res.data.line_total_incl_tax === 'number') { $cb.attr('data-price', res.data.line_total_incl_tax); updateSelectedSummary(); } // 数量为0时移除商品行 if (val === 0 || res.data.removed) { row.fadeOut(300, function(){ $(this).remove(); snapshotCartFromDOM(); updateSelectedSummary(); }); } else { snapshotCartFromDOM(); } } else { var msg = (res && res.data && (res.data.message || res.data)) || '数量更新失败'; alert(msg); } }).fail(function(){ alert('数量更新失败,请重试'); }).always(function(){ // 隐藏加载动画并启用输入框 $quantityContainer.find('.quantity-saving-overlay').hide(); $input.prop('disabled', false); }); }, 500); // 0.5秒延迟 }); // 新增错误提示函数 function showError(msg) { if (!$('#qty-error').length) { $('body').append(''); } $('#qty-error').text(msg).fadeIn(200).delay(3000).fadeOut(400); } // Partial checkout -> regular checkout page $('#partial-checkout').off('click.sc').on('click.sc', function(e){ e.preventDefault(); var keys = getSelectedKeys(); if (!keys.length) { alert('请至少选择一件商品结算'); return; } var $btn = $(this), t = $btn.text(); $btn.prop('disabled', true).text('创建订单中...'); // Snapshot first for safety snapshotCartFromDOM(); $.ajax({ url: PC.ajax_url, method: 'POST', dataType: 'json', data: { action: 'create_direct_order', selected_items: keys, security: PC.security } }).done(function(res){ if (res && res.success && res.data && res.data.checkout_url) { window.location.href = res.data.checkout_url; // This is /checkout/?pc_token=... } else { alert((res && res.data && (res.data.message || res.data)) || '创建订单失败,请重试'); $btn.prop('disabled', false).text(t); } }).fail(function(xhr){ var msg = '创建订单失败'; if (xhr && xhr.responseJSON && xhr.responseJSON.data) { msg += ':' + (xhr.responseJSON.data.message || xhr.responseJSON.data); } alert(msg); $btn.prop('disabled', false).text(t); }); }); // Keep LS selection after removing via the "x" link and update cart snapshot $(document).on('click', 'a.remove', function(){ var key = $(this).closest('tr.cart_item').attr('data-cart_item_key'); if (key) { var saved = readSelection().filter(function(k){ return k !== key; }); writeSelection(saved); snapshotCartFromDOM(); } }); // Init restoreSelectionFromLS(); updateSelectedSummary(); snapshotCartFromDOM(); maybeRehydrateFromLocal(); }); </script> functions.php <?php defined('ABSPATH') || exit; /** * Robust partial checkout to regular /checkout/ with durable cart snapshot * - Snapshot full cart before virtualizing selection for checkout * - Do not remove anything until order is created * - On success (thank-you), rebuild cart as (snapshot - purchased) * - On cancel/back (visit cart), restore snapshot * - Guest resilience: localStorage + rehydrate AJAX */ /* ------------------------------------------------- * Helpers * ------------------------------------------------- */ function pc_get_cart_uid() { if (is_user_logged_in()) { return 'user_' . get_current_user_id(); } if (empty($_COOKIE['pc_cart_uid'])) { $token = wp_generate_uuid4(); setcookie('pc_cart_uid', $token, time() + YEAR_IN_SECONDS, COOKIEPATH ?: '/', '', is_ssl(), false); $_COOKIE['pc_cart_uid'] = $token; } return 'guest_' . sanitize_text_field(wp_unslash($_COOKIE['pc_cart_uid'])); } function pc_build_item_key($product_id, $variation_id = 0) { return (int)$product_id . '|' . (int)$variation_id; } function pc_snapshot_current_cart() { if (!WC()->cart) wc_load_cart(); $items = array(); foreach (WC()->cart->get_cart() as $ci_key => $ci) { $pid = isset($ci['product_id']) ? (int)$ci['product_id'] : 0; $vid = isset($ci['variation_id']) ? (int)$ci['variation_id'] : 0; $qty = isset($ci['quantity']) ? wc_stock_amount($ci['quantity']) : 0; $var = isset($ci['variation']) && is_array($ci['variation']) ? $ci['variation'] : array(); if ($pid && $qty > 0) { $items[] = array( 'product_id' => $pid, 'variation_id' => $vid, 'variation' => array_map('wc_clean', $var), 'quantity' => $qty, ); } } return $items; } function pc_restore_cart_from_items($items) { if (!WC()->cart) wc_load_cart(); WC()->cart->empty_cart(); foreach ((array)$items as $it) { $pid = isset($it['product_id']) ? (int)$it['product_id'] : 0; $vid = isset($it['variation_id']) ? (int)$it['variation_id'] : 0; $qty = isset($it['quantity']) ? wc_stock_amount($it['quantity']) : 0; $var = isset($it['variation']) && is_array($it['variation']) ? array_map('wc_clean', $it['variation']) : array(); if ($pid && $qty > 0) { WC()->cart->add_to_cart($pid, $qty, $vid, $var); } } WC()->cart->calculate_totals(); } function pc_transient_key($token) { return 'pc_partial_payload_' . sanitize_key($token); } /* ------------------------------------------------- * AJAX: Local rehydrate when Woo cart is empty * ------------------------------------------------- */ add_action('wp_ajax_pc_rehydrate_cart', 'pc_rehydrate_cart'); add_action('wp_ajax_nopriv_pc_rehydrate_cart', 'pc_rehydrate_cart'); function pc_rehydrate_cart() { check_ajax_referer('woocommerce-cart', 'security'); $raw = isset($_POST['items']) ? wp_unslash($_POST['items']) : ''; $items = is_string($raw) ? json_decode($raw, true) : (array)$raw; if (!is_array($items)) { wp_send_json_error(array('message' => 'Invalid items.'), 400); } if (!WC()->cart) wc_load_cart(); if (!WC()->cart->is_empty()) { wp_send_json_success(array('message' => 'Cart not empty.')); } foreach ($items as $it) { $pid = isset($it['product_id']) ? (int)$it['product_id'] : 0; $vid = isset($it['variation_id']) ? (int)$it['variation_id'] : 0; $qty = isset($it['quantity']) ? wc_stock_amount($it['quantity']) : 0; $var = isset($it['variation']) && is_array($it['variation']) ? array_map('wc_clean', $it['variation']) : array(); if ($pid && $qty > 0) { WC()->cart->add_to_cart($pid, $qty, $vid, $var); } } WC()->cart->calculate_totals(); wp_send_json_success(array('rehydrated' => true)); } /* ------------------------------------------------- * AJAX: Update qty (per-row; no page reload) * ------------------------------------------------- */ add_action('wp_ajax_update_cart_item_qty', 'pc_update_cart_item_qty'); add_action('wp_ajax_nopriv_update_cart_item_qty', 'pc_update_cart_item_qty'); function pc_update_cart_item_qty() { check_ajax_referer('woocommerce-cart', 'security'); $key = isset($_POST['cart_item_key']) ? wc_clean(wp_unslash($_POST['cart_item_key'])) : ''; $qty = isset($_POST['qty']) ? wc_stock_amount($_POST['qty']) : null; if (!$key || $qty === null) { wp_send_json_error(array('message' => 'Missing params.'), 400); } if (!WC()->cart) wc_load_cart(); if ($qty <= 0) { $removed = WC()->cart->remove_cart_item($key); WC()->cart->calculate_totals(); wp_send_json_success(array('removed' => (bool)$removed)); } else { $set = WC()->cart->set_quantity($key, $qty, true); WC()->cart->calculate_totals(); $cart_item = WC()->cart->get_cart_item($key); if (!$cart_item) { wp_send_json_error(array('message' => 'Cart item not found after update.'), 404); } $_product = $cart_item['data']; $subtotal_html = apply_filters('woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal($_product, $cart_item['quantity']), $cart_item, $key); // Use line_total + line_tax (after totals) for your checkbox data-price $line_total_incl_tax = (float)($cart_item['line_total'] + $cart_item['line_tax']); // functions.php 中的更新 wp_send_json_success(array( 'subtotal_html' => $subtotal_html, 'line_total_incl_tax' => $line_total_incl_tax, 'removed' => ($qty <= 0) // 明确返回是否移除 )); } } /* ------------------------------------------------- * AJAX: Remove selected * ------------------------------------------------- */ add_action('wp_ajax_remove_selected_cart_items', 'pc_remove_selected_cart_items'); add_action('wp_ajax_nopriv_remove_selected_cart_items', 'pc_remove_selected_cart_items'); function pc_remove_selected_cart_items() { check_ajax_referer('woocommerce-cart', 'security'); $keys = isset($_POST['selected_items']) ? (array) $_POST['selected_items'] : array(); if (!WC()->cart) wc_load_cart(); foreach ($keys as $k) { $k = wc_clean(wp_unslash($k)); WC()->cart->remove_cart_item($k); } WC()->cart->calculate_totals(); wp_send_json_success(true); } /* ------------------------------------------------- * AJAX: Empty cart * ------------------------------------------------- */ add_action('wp_ajax_empty_cart', 'pc_empty_cart'); add_action('wp_ajax_nopriv_empty_cart', 'pc_empty_cart'); function pc_empty_cart() { check_ajax_referer('woocommerce-cart', 'security'); if (!WC()->cart) wc_load_cart(); WC()->cart->empty_cart(); wp_send_json_success(true); } /* ------------------------------------------------- * AJAX: Apply coupon * ------------------------------------------------- */ add_action('wp_ajax_apply_coupon', 'pc_apply_coupon'); add_action('wp_ajax_nopriv_apply_coupon', 'pc_apply_coupon'); function pc_apply_coupon() { check_ajax_referer('woocommerce-cart', 'security'); $code = isset($_POST['coupon_code']) ? wc_format_coupon_code(wp_unslash($_POST['coupon_code'])) : ''; if (!$code) { wp_send_json_error(array('message' => __('请输入优惠券代码', 'woocommerce')), 400); } if (!WC()->cart) wc_load_cart(); $applied = WC()->cart->apply_coupon($code); WC()->cart->calculate_totals(); if (is_wp_error($applied)) { wp_send_json_error(array('message' => $applied->get_error_message()), 400); } if (!$applied) { // Woo often pushes notices instead of bool; we return generic message wp_send_json_error(array('message' => __('优惠券应用失败', 'woocommerce')), 400); } wp_send_json_success(true); } /* ------------------------------------------------- * AJAX: Start partial checkout to regular checkout page * - Save snapshot + selected items in a transient keyed by token * - Put token in session * - Return /checkout/?pc_token=... * ------------------------------------------------- */ add_action('wp_ajax_create_direct_order', 'pc_create_direct_order'); add_action('wp_ajax_nopriv_create_direct_order', 'pc_create_direct_order'); function pc_create_direct_order() { check_ajax_referer('woocommerce-cart', 'security'); $selected_keys = isset($_POST['selected_items']) ? (array) $_POST['selected_items'] : array(); if (empty($selected_keys)) { wp_send_json_error(array('message' => __('请选择要结算的商品', 'woocommerce')), 400); } if (!WC()->cart) wc_load_cart(); // Snapshot full cart $snapshot = pc_snapshot_current_cart(); // Build selected items from current cart based on cart_item_key list $selected = array(); foreach (WC()->cart->get_cart() as $ci_key => $ci) { if (!in_array($ci_key, $selected_keys, true)) { continue; } $pid = (int)$ci['product_id']; $vid = (int)$ci['variation_id']; $qty = wc_stock_amount($ci['quantity']); $var = isset($ci['variation']) && is_array($ci['variation']) ? array_map('wc_clean', $ci['variation']) : array(); if ($pid && $qty > 0) { $selected[] = array( 'product_id' => $pid, 'variation_id' => $vid, 'variation' => $var, 'quantity' => $qty, ); } } if (empty($selected)) { wp_send_json_error(array('message' => __('没有可结算的商品', 'woocommerce')), 400); } $token = wp_generate_uuid4(); $payload = array( 'uid' => pc_get_cart_uid(), 'snapshot' => $snapshot, 'selected' => $selected, 'created' => time(), ); set_transient(pc_transient_key($token), $payload, 2 * DAY_IN_SECONDS); // Put token in session (used across checkout AJAX calls) if (method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', $token); } $checkout_url = add_query_arg('pc_token', rawurlencode($token), wc_get_checkout_url()); wp_send_json_success(array('checkout_url' => $checkout_url)); } /* ------------------------------------------------- * Virtualize cart on the regular checkout for token * - On initial checkout load with ?pc_token=... * - Ensure re-virtualization before checkout processing * - Tag order with token * - On thank-you, rebuild cart = snapshot - purchased * - On returning to cart without completing: restore snapshot * ------------------------------------------------- */ // Entering checkout with token: virtualize cart to selected items add_action('woocommerce_before_checkout_form', function() { if (!isset($_GET['pc_token'])) return; $token = sanitize_text_field(wp_unslash($_GET['pc_token'])); $payload = get_transient(pc_transient_key($token)); if (empty($payload) || empty($payload['selected'])) return; if (!WC()->cart) wc_load_cart(); // Virtualize to selected items only pc_restore_cart_from_items($payload['selected']); // Persist token in session for all subsequent checkout AJAX calls if (method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', $token); } }, 1); // Safety: just-in-time re-virtualization before order processing add_action('woocommerce_before_checkout_process', function() { if (!method_exists(WC()->session, 'get')) return; $token = WC()->session->get('pc_partial_token'); if (!$token) return; $payload = get_transient(pc_transient_key($token)); if (empty($payload) || empty($payload['selected'])) return; // Ensure cart still equals selected set (another tab might have restored) pc_restore_cart_from_items($payload['selected']); }, 1); // Tag order with token so we can resolve on thank-you add_action('woocommerce_checkout_create_order', function($order /* WC_Order */) { $token = null; if (isset($_GET['pc_token'])) { $token = sanitize_text_field(wp_unslash($_GET['pc_token'])); } elseif (method_exists(WC()->session, 'get')) { $token = WC()->session->get('pc_partial_token'); } if ($token) { $order->update_meta_data('_pc_partial_token', $token); } }, 10, 1); // On thank-you: rebuild cart as (snapshot - purchased), then cleanup add_action('woocommerce_thankyou', function($order_id) { $order = wc_get_order($order_id); if (!$order) return; $token = $order->get_meta('_pc_partial_token'); if (!$token) return; $payload = get_transient(pc_transient_key($token)); if (empty($payload) || empty($payload['snapshot'])) { // Nothing to rebuild, just cleanup session token if (method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); return; } // Build purchased map pid|vid => qty $purchased = array(); foreach ($order->get_items('line_item') as $item) { $pid = (int)$item->get_product_id(); $vid = (int)$item->get_variation_id(); $qty = (int)$item->get_quantity(); $k = pc_build_item_key($pid, $vid); if (!isset($purchased[$k])) $purchased[$k] = 0; $purchased[$k] += $qty; } // Remainder = snapshot - purchased $remainder = array(); foreach ($payload['snapshot'] as $it) { $pid = (int)$it['product_id']; $vid = (int)$it['variation_id']; $qty = wc_stock_amount($it['quantity']); $var = isset($it['variation']) ? $it['variation'] : array(); $k = pc_build_item_key($pid, $vid); $take = isset($purchased[$k]) ? (int)$purchased[$k] : 0; $left = max(0, $qty - $take); if ($left > 0) { $remainder[] = array( 'product_id' => $pid, 'variation_id' => $vid, 'variation' => $var, 'quantity' => $left, ); $purchased[$k] = max(0, $take - $qty); // if over-purchased (unlikely), keep non-negative } } // Rebuild cart to remainder pc_restore_cart_from_items($remainder); // Cleanup token if (method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); // Also update localStorage best-effort on the thank-you page (client side) is optional; // your cart.php JS already re-snapshots on next visit. }, 20); // If user visits the cart page with an active partial token (abandoned/cancelled), restore full snapshot add_action('woocommerce_before_cart', function() { if (!method_exists(WC()->session, 'get')) return; $token = WC()->session->get('pc_partial_token'); if (!$token) return; $payload = get_transient(pc_transient_key($token)); if (empty($payload) || empty($payload['snapshot'])) return; // Restore full snapshot so cart page always shows everything pc_restore_cart_from_items($payload['snapshot']); // Keep token so user can retry checkout; or clear it if you prefer ending the flow here: // WC()->session->set('pc_partial_token', null); }, 1); Currently You are now a website builder. These are the code in my cart.php & functions.php. Currently, i am very satisfied with my layout. However, I want to achieve cart like Shopee / Taobao / Lazada, that allow my customer to 1) Do selective checkout, where only selected items are sent to checkout page, and after order created, only these items will be removed from cart. On the other side, non-selected items are retained inside cart, until customer remove them manually through 清除購物車 / 移除選中商品 or customer check out them. Only remove when order is created. If customer go back from checkout page or payment page, or anything, as long as order is not created, dont remove them. Currently im using restore cart way to achieve this, but everything from cart is removed currently after order created. theres some mistake that stop me from achieving this. I turned on feature where customer can see how many items are inside cart through the cart icon at header. At the same time, i dont want my customer to notice that their cart is cleared and recovered before (the amount of items in cart icon will show 0 when havent recover and the number of items after recover). I dont want them to notice the change, therefore, we have to recover it fast until customer did not notice them. Please be considerate regarding customer that use PC because they might access my website through another tab, at there, they can see the amount of items in cart icon. Therefore, i want it to always show the correct amount, only remove when the order is created and maintain if the order is not created. I dont want them to notice how it works (recovering) 2) All these 全选 刪除選中的商品 清空購物車 输入优惠券代码 应用优惠券 已选商品: 0 件,共计: RM0.00 结算 works perfectly fine, please remain them. Maintaining all the layout and achieved functions. Please check which part stopped me from achieving the selective checkout (maintain non-selected items inside cart, only remove selected to checkout items when order created, and dont let customer nmotice the change in their cart. I want them to no matter access from where, either new tab, other device etc, they will see the correct items in their cart) For now, If i cancel the payment halfway, i am logged out when back from payment page, and when i check from other tab, non-selected items are removed from cart, only selected items are still inside cart. Also, when i login back after payment page, it redirects me to pay-only page. Please refer how taobao cart works, and review which part is stopping me from achieve taobao cart, give me the part of code to be changed and the new code to replaced with the current one.

请你帮我把这个运行成可下载的PDF:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Research Hypothesis: MgSO₄ in Chemotherapy-Induced Neuropathic Pain</title> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/mermaid.min.js"></script> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background-color: #f8f9fa; margin: 0; padding: 20px; display: flex; flex-direction: column; align-items: center; } .container { max-width: 1200px; width: 100%; background-color: white; border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); padding: 30px; margin-top: 20px; } header { text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 20px; } h1 { color: #2c3e50; margin-bottom: 10px; } .subtitle { color: #7f8c8d; font-size: 1.2em; margin-top: 0; } .diagram-container { width: 100%; min-height: 500px; background-color: #f5f7fa; border-radius: 8px; padding: 20px; margin: 20px 0; } .legend { display: flex; justify-content: center; flex-wrap: wrap; gap: 15px; margin: 20px 0; padding: 15px; background-color: #e8f4fc; border-radius: 8px; } .legend-item { display: flex; align-items: center; gap: 8px; font-size: 14px; } .color-box { width: 20px; height: 20px; border-radius: 4px; } .key-points { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 30px; } .card { background-color: #f8f9fa; border-left: 4px solid #3498db; padding: 15px; border-radius: 4px; } .card h3 { margin-top: 0; color: #2c3e50; } footer { text-align: center; margin-top: 30px; color: #7f8c8d; font-size: 0.9em; padding-top: 20px; border-top: 1px solid #ecf0f1; } @media print { body { padding: 0; margin: 0; } .container { box-shadow: none; padding: 10px; } .no-print { display: none; } } </style> </head> <body>
Research Hypothesis: MgSO₄ in Chemotherapy-Induced Neuropathic Pain (CINP) Mechanism of Action and Protective Effects
flowchart TD %% Chemotherapy Induction A[Oxaliplatin
Chemotherapy] --> B %% Core Mechanism Pathway subgraph B[Chemotherapy-Induced Neuropathic Pain] direction TB C[TNF-α Release] --> D[TNFR1 Activation] D --> E[Fyn Kinase Activation] E --> F[NR2B Phosphorylation
(pTyr1472)] F --> G[NMDA Receptor
Hyperactivation] G --> H[Ca²⁺ Influx] H --> I[Neuronal Apoptosis] H --> J[Autophagy Flux
Disruption] I --> K[Neuropathic Pain] J --> K end %% Magnesium Intervention L[MgSO₄ Intervention] -->|Inhibits NF-κB Pathway| C L -->|Blocks Ion Channel| G %% Pain Outcome K --> M((Persistent
Neuropathic Pain)) %% Style enhancements classDef chem fill:#f8d7da,stroke:#721c24,color:#721c24; classDef process fill:#cfe2ff,stroke:#052c65,color:#052c65; classDef effect fill:#fff3cd,stroke:#856404,color:#856404; classDef pain fill:#d1ecf1,stroke:#0c5460,color:#0c5460; classDef intervention fill:#d4edda,stroke:#155724,color:#155724; class A chem; class B process; class C,D,E,F,G process; class H,I,J effect; class K,M pain; class L intervention;
Chemotherapy Induction Core Molecular Processes Cellular Effects Pain Outcome MgSO₄ Intervention Core Pathogenic Mechanism The "TNF-α → pNR2B-NMDA → Cellular Damage" axis is central to chemotherapy-induced neuropathic pain development: TNF-α activates TNFR1 receptors Fyn kinase phosphorylates NR2B subunit (pTyr1472) NMDA receptor hyperfunction causes Ca²⁺ overload Leads to neuronal apoptosis & autophagy disruption MgSO₄ Dual-Action Intervention Magnesium sulfate provides dual protective effects: Anti-inflammatory action: Inhibits TNF-α release via NF-κB pathway suppression Receptor modulation: Blocks NMDA receptor ion channel as non-competitive antagonist Targets both arms of the pathogenic pathway Research Implications This study will validate: The causal relationship in the TNF-α/pNR2B pathway MgSO₄ efficacy in preventing CINP development Downstream cellular protection mechanisms Potential for clinical translation
This diagram illustrates the proposed mechanism of chemotherapy-induced neuropathic pain and the protective effects of magnesium sulfate To save as PDF: Use browser's Print function and select "Save as PDF"
<script> mermaid.initialize({ startOnLoad: true, theme: 'default', flowchart: { useMaxWidth: true, curve: 'linear', nodeSpacing: 50, rankSpacing: 70 }, securityLevel: 'loose' }); </script> </body> </html>

<template> <view class="content"> <view class="alarmInformation"> <view class="title"> <text>预警信息</text> </view> <view class="alarmDetail"> <view class="alarmDetailItem"> <text>报警类型:</text> <text>{{detailData.alarmtype}}</text> </view> <view class="alarmDetailItem"> <text>风险等级:</text> <text>{{detailData.risklevel}}</text> </view> <view class="alarmDetailItem"> <text>报警次数:</text> <text>{{detailData.alarmcount}}</text> </view> <view class="alarmDetailItem"> <text>持续时间:</text> <text>{{detailData.duration}}</text> </view> <view class="alarmDetailItem"> <text>报警时间:</text> <text>{{detailData.firsttime}}至{{detailData.lasttime}}</text> </view> <view class="alarmDetailItem"> <text>开始位置:</text> <text>{{detailData.firstlocation}}</text> </view> <view class="alarmDetailItem"> <text>结束位置:</text> <text>{{detailData.lastlocation}}</text> </view> <view class="alarmDetailItem"> <text>报警车速:</text> <text>{{startspeed}}</text> </view> <view class="alarmDetailItem" v-if="detailData.powerprocessed == '3OL4M8GZ'"> <text>热值:</text> <input style="border: 1px solid #ddd;width:88%;border-radius: 4px;padding:5px;" placeholder-style="color:#999;font-size:22upx" placeholder="请输入热值" v-model="detailData.calorific"></input> </view> <view > <text style="font-weight: 700;font-size: 30upx;">原因分析:</text> <textarea style="border: 1px solid #ddd;width:92%;padding:10px;border-radius: 4px;" auto-height='true' name="measure" v-model="detailData.remarks" placeholder-style="color:#999;font-size:28upx" placeholder="请输入原因分析..." /> </view> <view> <text style="font-weight: 700;font-size: 30upx;">整改措施:</text> <textarea style="border: 1px solid #ddd;width:92%;padding:10px;border-radius: 4px;" auto-height='true' name="measure" v-model="detailData.measures" placeholder-style="color:#999;font-size:28upx" placeholder="请输入整改措施..." /> </view> <view> <text style="font-weight: 700;font-size: 30upx;">处理说明:</text> <textarea style="border: 1px solid #ddd;width:92%;padding:10px;border-radius: 4px;" auto-height='true' name="measure" v-model="detailData.instructions" placeholder-style="color:#999;font-size:28upx" placeholder="请输入处理说明..." /> </view> <view style="margin-top: 28rpx;"><text style="font-size: 34rpx;font-weight: bold;">处理附件:</text></view> <view style="display: flex;width: 580rpx;flex-wrap: wrap;"> <view v-for="(photo, index) in detailData.penaltyfjList" :key="index" class="loop-img-box"> <image style="margin-right: 10px;" class="img-list" :src="photo" @tap="previewPhoto(detailData.penaltyfjList, index)" mode="aspectFill"></image> <view v-if="num > 0" class="q-image-remover" :data-idx="index" @click="btnDeleteImg(index)"> <image class="delete-img" src="@/static/delete_1.jpg" mode="aspectFill"></image> </view> </view> <image class="img-list" @tap="chooth(num)" src="@/static/jiazhao.png" mode="aspectFill" v-if="detailData.penaltyfjList.length < num"></image> </view> </view> </view> <view class="footer_btn" > <view class="dispose_btn" @click="<strong>btnQd</strong>()"> 确定 </view> </view> </view> </template> <script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&key=NCVBZ-PXCKW-O2KRT-3SN3X-JLFM3-NNB5G"></script> <script> // import { getUserInfo } from '@/request/api.js' import request from '@/http/request.js' export default { data() { return { photoData:[], num:9, Arr:[], detailData: { penaltyfjList:[] }, status: '', remark: '', formDisposeData: {}, disposeId: '', picList: [], videoList: [], showMap: false, latitude: '', longitude: '', points: [], polyline: [], markers: [], mapContext: null, nextPointIndex: 1, //下一个坐标点的索引 duratioinTime: 1000, //相邻两点动画持续时长默认1秒 showPlay: true, //默认显示播放按钮 pl: [], mapScale: 17, startspeed: '', firstgeopoint: '', car: '', photoArray:[], File:[], scId:[], cysstatus:"", lx:"", formDisposeData1:{}, showEmpty: false, isForwarding: false, //正在快进中 isBacking: false, //正在快退中 isEnding: false, //播放结束 pointCount: 10 ,//快进的点位数 lx:'', ryid:"", } }, async onLoad(option) { uni.showLoading({ title: '加载中' }) var my = this this.mapContext = uni.createMapContext('mymap', this) this.disposeId = option.ddid this.lx = option.lx ? option.lx : '' await my.loadDetail(option.ddid) var user = uni.getStorageSync('user') console.log(user) my.ryid = user[0].id }, methods: { btnJxcs(){ }, async btnQd(){ var my = this; var formDisposeData = {} if(my.lx !=='' && my.detailData.powerprocessed =='3OL4M8GY'){ if(my.lx =='cl'){ formDisposeData.id = my.disposeId formDisposeData.ryid = my.ryid formDisposeData.remarks =my.detailData.remarks formDisposeData.powerresults = '3T4000CQ' formDisposeData.penaltyfj = my.scId.join(',') formDisposeData.measures=my.detailData.measures, formDisposeData.instructions=my.detailData.instructions, request.vsportal('XcxJgAction.addJgdcl', formDisposeData).then(function(res) { if (res.status) { uni.showToast({ title: "处理成功!", icon: "success", }) uni.$emit('refreshPreviousPage', { data: 'dispose' }); setTimeout(function() { uni.navigateBack({ url: "/https/wenku.csdn.net/pages/prewarning/index" }); }, 500); } }) }else if(my.lx =='xg'){ formDisposeData.id = my.disposeId formDisposeData.ryid = my.ryid formDisposeData.remarks =my.detailData.remarks formDisposeData.penaltyfj = my.scId.join(',') formDisposeData.measures=my.detailData.measures formDisposeData.instructions=my.detailData.instructions request.vsportal('XcxJgAction.editWarn', formDisposeData).then(function(res) { if (res.status) { uni.showToast({ title: "处理成功!", icon: "success", }) uni.$emit('refreshPreviousPage', { data: 'dispose' }); setTimeout(function() { uni.navigateBack({ url: "/https/wenku.csdn.net/pages/prewarning/index" }); }, 500); } }) }else if(my.lx =='jcbj'){ formDisposeData.id = my.disposeId formDisposeData.ryid = my.ryid formDisposeData.powerresults = '3T4000CP' formDisposeData.remarks = my.detailData.remarks formDisposeData.penaltyfj = my.scId.join(',') formDisposeData.measures=my.detailData.measures, formDisposeData.instructions=my.detailData.instructions, request.vsportal('XcxJgAction.addJgdcl', formDisposeData).then(function(res) { if (res.status) { uni.showToast({ title: "处理成功!", icon: "success", }) uni.$emit('refreshPreviousPage', { data: 'dispose' }); setTimeout(function() { uni.navigateBack({ url: "/https/wenku.csdn.net/pages/prewarning/index" }); }, 500); } }) } } await request.vsportal('XlAction.editysabn', { measures:my.detailData.measures, remarks:my.detailData.remarks, instructions:my.detailData.instructions, calorific:my.detailData.calorific ? my.detailData.calorific :'', id:my.disposeId, penaltyfj:my.scId.join(',') }).then(function(res) { uni.navigateBack() }) }, chooth(num) { console.log(this.detailData) this.Arr = [] var number = this.num - this.detailData.penaltyfjList.length var my = this var array = [] my.photoArray = [] my.File = [] uni.chooseImage({ count: number, //默认9 sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有 success: function (res) { //图片数组 console.log(res,'11') uni.showLoading({ title: '上传中...', mask: true }) let tempFilePath = res.tempFilePaths let Arr1 = [] for (var i = 0; i < res.tempFilePaths.length; i++) { my.detailData.penaltyfjList.push(res.tempFilePaths[i]) Arr1.push(res.tempFilePaths[i]) } setTimeout(function () { my.tpsc(Arr1) }, 600) } }) }, //图片上传 tpsc(tps) { var url = request.HttpHost + '/portal.php?resid=fileUpload.uploader' this.digui(0, tps, url) }, //异步递归 digui(index, arr, url) { if (index == arr.length) { uni.hideLoading() // console.log(this.scId); // console.log(this.typeimg); //this.$emit('tijiaoImg', this.scId, this.typeimg) return } var my = this //console.log('上传图片filePath===',arr[index]) uni.uploadFile({ url: url, filePath: arr[index], name: 'file', success: (uploadFileRes) => { //console.log("上传success=====",uploadFileRes) var res = JSON.parse(uploadFileRes.data) this.scId.push(res.data.id) console.log(this.scId) index++ // console.log(index); my.digui(index, arr, url) }, fail: (res) => { console.log("上传fail=====",res) } }) }, // 预览图片 previewPhoto(arr, index) { uni.previewImage({ current: index, //预览图片的下标 urls: arr //预览图片的地址,必须要数组形式,如果不是数组形式就转换成数组形式就可以 // loop:true, }) // this.$forceUpdate()this }, // 删除照片 btnDeleteImg(index) { // console.log(this.scId); var my = this my.detailData.penaltyfjList.splice(index, 1) my.scId.splice(index, 1) }, zpurl(zp) { let zpurl = new Array(zp.length); for (let i = 0; i < zp.length; i++) { zpurl[i] = request.imageUrl(zp[i]); } return zpurl; }, async loadDetail(id) { var my = this; await request.vsportal('XcxJgAction.warnDetail', { id: id }).then(function(res) { uni.hideLoading() if (res.status) { my.detailData = res.data[0] if(!my.detailData.calorific) my.detailData.calorific = '0' if(my.detailData.penaltyfj && my.detailData.penaltyfj !=='')my.scId = my.detailData.penaltyfj.split(',') if(my.detailData.penaltyfj && my.detailData.penaltyfj !==''){ var arr = my.detailData.penaltyfj.split(',') my.detailData.penaltyfjList = my.zpurl(arr) }else{ my.detailData.penaltyfjList = [] } if(my.detailData.firsttime)my.detailData.firsttime = my.formatDate(my.detailData.firsttime) if(my.detailData.lasttime)my.detailData.lasttime = my.formatDate(my.detailData.lasttime) if (res.data[0].firstlocation.indexOf('[]') != -1) { my.detailData.firstlocation = '' } if (res.data[0].lastlocation.indexOf('[]') != -1) { my.detailData.lastlocation = '' } my.startspeed = my.detailData.startspeed != "" ? my.detailData.startspeed + 'km/h' : "0km/h" } }); }, formatDate(value) { if (value == undefined) { return; } // let date = new Date(value * 1000); let date = new Date(value); //时间戳为10位需*1000,时间戳为13位的话不需乘1000 let y = date.getFullYear(); let MM = date.getMonth() + 1; MM = MM < 10 ? ('0' + MM) : MM; //月补0 let d = date.getDate(); d = d < 10 ? ('0' + d) : d; //天补0 let h = date.getHours(); h = h < 10 ? ('0' + h) : h; //小时补0 let m = date.getMinutes(); m = m < 10 ? ('0' + m) : m; //分钟补0 let s = date.getSeconds(); s = s < 10 ? ('0' + s) : s; //秒补0 console.log(y + '-' + MM + '-' + d + ' ' + h + ':' + m + ":" + s) return y + '-' + MM + '-' + d + ' ' + h + ':' + m + ":" + s; //年月日时分秒 }, splitString(fileList) { var my = this; //my.picList.push("http://n.sinaimg.cn/ent/4_img/upload/1f0ce517/251/w1024h827/20210413/a255-knqqqmv1931923.jpg") for (var i = 0; i < fileList.length; i++) { console.log(fileList[i].fileurl) var file = fileList[i].fileurl if (file.includes("png") || file.includes("jpg")) { my.picList.push(file); } else if (file.includes("mp4")) { my.videoList.push({ path: file, id: 'myVideo' + i }) } } }, } } </script> <style lang="scss"> .loop-img-box { position: relative; width: 160rpx !important; height: 110rpx !important; margin-right: 10px; margin-bottom: 7px; } .img-list { display: block; position: relative; padding: 15rpx ; width: 160rpx !important; height: 110rpx !important; //padding-right: 15rpx; /* vertical-align: bottom; */ } .q-image-remover { width: 48rpx; height: 48rpx; } .delete-img { width: 48rpx; height: 48rpx; position: absolute; top:-4px; right: -16px; // padding: 10rpx; } .img { width: 140rpx; height: 110rpx; padding: 15rpx; } .popup-content2 { background-color: #fff; width: 686upx; border-radius: 28upx; padding: 50upx 38upx; box-sizing: border-box; .reason { display: flex; flex-direction: column; text { font-size: 34upx; font-weight: bold; } text:nth-child(2) { display: inline-block; width: 172upx; height: 60upx; line-height: 60upx; color: #FFF; border-radius: 40upx; font-size: 28upx; text-align: center; background-color: #2257FF; font-weight: normal; margin-top: 30upx; } } .btn { display: flex; justify-content: space-around; margin-top: 54upx; view { width: 252upx; height: 80upx; border-radius: 40upx; border: 1px solid #2257FF; line-height: 80upx; text-align: center; color: #2257FF; } .submit { background-color: #2257FF; color: #fff; } } } .popup-save { @include flex; align-items: center; justify-content: center; padding: 15px; height: 50px; background-color: #fff; } // 分界线 .boundary { width: 100%; height: 24upx; background-color: #ddd; } .content { width: 100%; box-sizing: border-box; padding-bottom: 80upx; .jgdDisposeInformation { padding: 0 32upx; .title { margin-top: 20upx; text { font-size: 34upx; color: #333333; font-weight: 900; } } .remark { padding: 20upx 0; view { display: flex; text { display: inline-block; width: 150upx; } text:nth-child(2) { display: inline-block; width: 450upx; } } } } .orderInfomation { padding: 0 32upx; .title { margin-top: 20upx; text { font-size: 34upx; color: #333333; font-weight: 900; } } .oderDetail { padding: 20upx 0; view { font-size: 32upx; color: #333333; font-weight: 400; line-height: 50upx; } .WaybillNumber, .name, .commonCarrier, .car { display: flex; justify-content: start; text:nth-child(1) { display: inline-block; width: 160upx; font-size: 30upx; font-weight: 700; } text:nth-child(2) { display: inline-block; width: auto; font-weight: 500; font-size: 30upx; } image { display: flex; width: 40upx; height: 40upx; justify-content: center; margin-left: 15upx; margin-top: 4upx; margin-right: 20upx; } } } } .alarmInformation { margin-top: 20upx; padding: 0 32upx; .title { text { font-size: 34upx; color: #333333; font-weight: 900; } } .alarmDetail { padding: 20upx 0; view { font-size: 32upx; color: #333333; font-family: PingFang SC; font-weight: 400; line-height: 50upx; } .alarmDetailItem { display: flex; justify-content: start; text:nth-child(1) { display: inline-block; width: 160upx; font-weight: 700; font-size: 30upx; } text:nth-child(2) { display: inline-block; width: 520upx; font-weight: 500; font-size: 30upx; } } } } .alarmAnnex { margin-top: 20upx; padding: 0 32upx; .title { text { font-size: 34upx; color: #333333; font-weight: 900; } } .annexDetail { padding: 20upx 0; image { display: inline-block; width: 100%; height: 516upx; } } .annexDetail_video { width: 100%; height: 516upx; margin-top: 48upx; } .annexDetail_map { position: relative; .map { margin-top: 20upx; width: 100%; height: 416upx; } image { width: 100upx; height: 100upx; position: absolute; top: 75%; left: 35%; z-index: 2; } } .empty { width: 500upx; height: 300upx; margin-left: 50%; margin-top: 35%; transform: translate(-50%, -50%); image { display: block; width: 100%; } text { display: block; width: 100%; text-align: center; margin: 0 auto; font-size: 28upx; color: #333333; } } .page-section { width: 100%; height: 300upx; } } .footer_btn { display: flex; flex-direction: column; margin-top: 86upx; padding: 0 32upx; view { height: 80upx; background-color: #2257FF; border-radius: 40upx; line-height: 80upx; text-align: center; color: #fff; } .overlook { background-color: #fff; color: #2257FF; border: 1px solid #2257FF; margin-top: 30upx; } } .map_button { justify-content: space-between; flex-direction: row; image:nth-child(1) { width: 80upx; height: 80upx; position: absolute; top: 90%; left: 30%; transform: translate(-50%, -50%); z-index: 55; } image:nth-child(2) { width: 80upx; height: 80upx; position: absolute; top: 90%; left: 50%; transform: translate(-50%, -50%); z-index: 55; } image:nth-child(3) { width: 80upx; height: 80upx; position: absolute; top: 90%; left: 70%; transform: translate(-50%, -50%); z-index: 55; } } } </style>哪里出问题了

<template> <myModal :params="{ title: '编辑流量计' }" :visible="visible" @submit="submit" @cancel="handleCancel"> <template v-slot:header> </template> <template v-slot:body> <a-form-model ref="baseInfoForm" :model="formData" :rules="rules" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" > {{ $t('基础信息') }} <a-row> <a-col :span="12"> <a-form-model-item :label="$t('探测器名称')" prop="detectorName"> <a-input v-model="formData.detectorName" disabled /> </a-form-model-item> </a-col> <a-col :span="12"> <a-form-model-item :label="$t('探测器编号')" prop="uniqueCode"> <a-input v-model="formData.uniqueCode" disabled /> </a-form-model-item> </a-col> <a-col :span="12"> <a-form-model-item :label="$t('流量计编号')" prop="meterCode"> <a-input v-model="formData.meterCode" disabled /> </a-form-model-item> </a-col> <a-col :span="12"> <a-form-model-item :label="$t('接入时间')" prop="rate"> <a-input v-model.trim="formData.rate" :placeholder="$t('请输入')" :allowClear="false" /> </a-form-model-item> </a-col> <a-col :span="12"> <a-form-model-item :label="$t('归属')" prop="rate"> <a-input v-model="formData.uniqueCode" disabled /> </a-form-model-item> </a-col> </a-row> {{ $t('子流量计列表') }} <a-button class="mgr10" type="primary" @click="onAdd">{{ $t('新增') }}</a-button> <a-popconfirm :title="$t('是否确认删除?')" :ok-text="$t('确定')" :cancel-text="$t('取消')" :visible="popconfirmVisible" @visibleChange="popconfirmVisibleChange" @confirm="onDeleteAll" > <a-button>{{ $t('删除') }}</a-button> </a-popconfirm> <a-table :dataSource="tableData" :rowSelection="rowSelection" rowKey="id" :columns="columns" :pagination="false" size="small" > <template slot="meterCode" slot-scope="text, record, index"> <template v-if="text">{{ text }}</template> <template v-else> <a-select v-model="tableData[index].meterCode" :filterOption="filterOption" @change="changeMemterCode" :placeholder="$t('请选择')" showSearch :allowClear="false" > <a-select-option v-for="item in meterOptions" :key="item.id" :value="item.meterCode" :title="item.meterCode" :disabled="item.disabled" > {{ item.meterCode }} </a-select-option> </a-select> </template> </template> <template slot="action" slot-scope="text, record"> <a-popconfirm placement="topRight" :title="$t('是否确认删除?')" :ok-text="$t('确定')" :cancel-text="$t('取消')" @confirm="onDelete(record)" > </a-popconfirm> </template> </a-table> </a-form-model> </template> </myModal> </template> <script> import factory from '../factory'; import myModal from '@/components/scfComponents/modalComponents/modal.vue'; export default { components: { myModal }, data() { return { visible: false, formData: {}, rules: { taskName: [ { required: true, message: '请输入任务名称', trigger: 'blur' }, // { pattern: reg.name, message: this.$t('仅允许输入汉字、字母、数字与_-.@字符') }, ], }, columns: [ { title: this.$t('序号'), key: 'index', dataIndex: 'index', customRender: (text, record, index) => ${index + 1}, }, { title: this.$t('子电表编号'), dataIndex: 'meterCode', key: 'meterCode', scopedSlots: { customRender: 'meterCode' }, }, { title: this.$t('操作'), key: 'action', width: 150, dataIndex: 'action', scopedSlots: { customRender: 'action' }, }, ], popconfirmVisible: false, meterOptions: [], selectedRowKeys: [], selectedRows: [], tableData: [], }; }, computed: { rowSelection() { return { onChange: this.rowSelectionChange, }; }, }, methods: { // 获取子电表列表 getChildMeterList(detectorCode) { let params = { detectorCodes: [detectorCode], page: 1, pageSize: 99999, }; factory.getChildMeterList(params).then(res => { if (res.success) { this.meterOptions = res.data.pageData.map(item => ({ ...item, disabled: false })) || []; } }); }, showModal() { this.getChildMeterList(record.detectorCode); this.visible = true; }, filterOption(input, option) { return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0; }, changeMemterCode(value) { let checkOption = this.meterOptions.find(el => el.meterCode === value); this.tableData.forEach(item => { if (item.meterCode === checkOption.meterCode) { item.detectorCode = checkOption.detectorCode; } }); let selectedItems = this.tableData.map(item => item.meterCode).filter(el => el !== null && el !== ''); this.meterOptions.forEach(el => { if (selectedItems.includes(el.meterCode)) { el.disabled = true; } }); }, // 全选/单选 rowSelectionChange(selectedRowKeys, selectedRows) { this.selectedRowKeys = selectedRowKeys; this.selectedRows = selectedRows; }, // 批量删除提示框 popconfirmVisibleChange(visible) { if (visible && !this.selectedRowKeys.length) { this.popconfirmVisible = false; this.$message.destroy(); this.$message.warning(this.$t('请选择要删除的信息')); } else { this.popconfirmVisible = visible; } }, // 新增 onAdd() { let isNull = this.tableData.filter(e => e.meterCode === null || e.meterCode === ''); if (isNull.length) return this.$message.warning(this.$t('请选择子电表编号')); this.tableData.push({ id: Math.random().toString().split('.')[1], meterCode: null }); }, onDeleteAll() { if (this.selectedRows.length === 0) { return this.$message.warning(this.$t('请选择子电表')); } let codes = this.selectedRows.map(item => item.id); this.tableData = this.tableData.filter(el => !codes.includes(el.id)); let selectedItems = this.selectedRows.map(item => item.meterCode).filter(el => el !== null && el !== ''); this.meterOptions.forEach(el => { if (selectedItems.includes(el.meterCode)) { el.disabled = false; } }); }, // 单个删除 onDelete(record) { this.tableData = this.tableData.filter(item => item.id !== record.id); if (record.meterCode) { this.meterOptions.forEach(el => { if (record.meterCode.indexOf(el.meterCode) !== -1) { el.disabled = false; } }); } }, submit() { this.visible = false; }, handleCancel() { this.visible = false; }, }, }; </script> <style lang="less" scoped> .edit-flow-meter-box { width: 100%; height: 100%; .table-title-box { width: 100%; display: flex; margin-bottom: 10px; align-items: center; justify-content: space-between; } }代码评审 </style>

最新推荐

recommend-type

优化算法基于四则运算的算术优化算法原理与Python实现:面向图像分割的全局寻优方法研究

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
recommend-type

Docker化部署TS3AudioBot教程与实践

### 标题知识点 #### TS3AudioBot_docker - **Dockerfile的用途与组成**:Dockerfile是一个文本文件,包含了所有构建Docker镜像的命令。开发者可以通过编辑Dockerfile来指定Docker镜像创建时所需的所有指令,包括基础镜像、运行时指令、环境变量、软件安装、文件复制等。TS3AudioBot_docker表明这个Dockerfile与TS3AudioBot项目相关,TS3AudioBot可能是一个用于TeamSpeak 3服务器的音频机器人,用于播放音频或与服务器上的用户进行交互。 - **Docker构建过程**:在描述中,有两种方式来获取TS3AudioBot的Docker镜像。一种是从Dockerhub上直接运行预构建的镜像,另一种是自行构建Docker镜像。自建过程会使用到docker build命令,而从Dockerhub运行则会用到docker run命令。 ### 描述知识点 #### Docker命令的使用 - **docker run**:这个命令用于运行一个Docker容器。其参数说明如下: - `--name tsbot`:为运行的容器指定一个名称,这里命名为tsbot。 - `--restart=always`:设置容器重启策略,这里是总是重启,确保容器在失败后自动重启。 - `-it`:这是一对参数,-i 表示交互式操作,-t 分配一个伪终端。 - `-d`:表示后台运行容器。 - `-v /home/tsBot/data:/data`:将宿主机的/home/tsBot/data目录挂载到容器内的/data目录上,以便持久化存储数据。 - `rofl256/tsaudiobot` 或 `tsaudiobot`:指定Docker镜像名称。前者可能是从DockerHub上获取的带有用户名命名空间的镜像,后者是本地构建或已重命名的镜像。 #### Docker构建流程 - **构建镜像**:使用docker build命令可以将Dockerfile中的指令转化为一个Docker镜像。`docker build . -t tsaudiobot`表示从当前目录中读取Dockerfile,并创建一个名为tsaudiobot的镜像。构建过程中,Docker会按顺序执行Dockerfile中的指令,比如FROM、RUN、COPY等,最终形成一个包含所有依赖和配置的应用镜像。 ### 标签知识点 #### Dockerfile - **Dockerfile的概念**:Dockerfile是一个包含创建Docker镜像所有命令的文本文件。它被Docker程序读取,用于自动构建Docker镜像。Dockerfile中的指令通常包括安装软件、设置环境变量、复制文件等。 - **Dockerfile中的命令**:一些常用的Dockerfile命令包括: - FROM:指定基础镜像。 - RUN:执行命令。 - COPY:将文件或目录复制到镜像中。 - ADD:类似于COPY,但是 ADD 支持从URL下载文件以及解压 tar 文件。 - ENV:设置环境变量。 - EXPOSE:声明端口。 - VOLUME:创建挂载点。 - CMD:容器启动时要运行的命令。 - ENTRYPOINT:配置容器启动时的执行命令。 ### 压缩包子文件的文件名称列表知识点 #### 文件命名 - **TS3AudioBot_docker-main**:此文件名表明了这是一个主要的代码库或Dockerfile的存放位置。在开发中,通常main分支代表当前的主版本或正在积极开发的分支。因此TS3AudioBot_docker-main可能表示这是在Dev分支上开发的Dockerfile的主要代码版本。主分支一般比较稳定,并作为新的特性开发的基础。 ### 综合知识点 - **Docker在DevOps中的角色**:Docker作为一种轻量级的容器化技术,在DevOps领域扮演重要角色。它可以快速部署、一致的运行环境、便于测试和迁移应用。通过Dockerfile的编写和docker build命令,开发者可以构建可移植的容器镜像,通过docker run命令则可以快速启动容器实例。 - **TS3AudioBot与TeamSpeak**:TS3AudioBot很可能是一个针对TeamSpeak 3服务器的自动化解决方案。TeamSpeak是一个语音通讯软件,广泛用于线上游戏团队进行沟通。一个音频机器人可以提供自动化的消息通知、音频流控制等功能,提高游戏社区的交流效率。 - **Docker镜像的版本管理**:镜像的命名通常包括用户名、项目名和标签。如rofl256/tsaudiobot中rofl256可能是一个用户名,tsaudiobot可能是项目名称,这样的命名规则有利于镜像的共享和管理。 在介绍以上知识点后,我们理解了标题、描述、标签及文件名称列表中所含的知识点。这些知识点涵盖了Dockerfile的构建、Docker镜像的使用、TS3AudioBot功能以及版本控制等多个方面,为IT专业人员在使用和开发Docker相关项目时提供了必要的信息。
recommend-type

零售销售数据的探索性分析与DeepAR模型预测

### 零售销售数据的探索性分析与DeepAR模型预测 #### 1. 探索性数据分析 在拥有45家商店的情况下,我们选择了第20号商店,来分析其不同部门在三年间的销售表现。借助DeepAR算法,我们可以了解不同部门商品的销售情况。 在SageMaker中,通过生命周期配置(Lifecycle Configurations),我们可以在笔记本实例启动前自定义安装Python包,避免在执行笔记本前手动跟踪所需的包。为了探索零售销售数据,我们需要安装最新版本(0.9.0)的seaborn库。具体操作步骤如下: 1. 在SageMaker的Notebook下,点击Lifecycle Config
recommend-type

llm agent平台

<think>好的,我现在需要帮用户寻找与LLM代理平台解决方案相关的信息。首先,我得明确用户的需求。用户提到了“LLM agent platform solutions”,也就是大型语言模型代理平台的解决方案。这可能涉及到如何构建、部署或优化基于LLM的代理系统。接下来,我应该回忆之前用户提供的引用内容,看看有没有相关的信息可以利用。 根据引用[1],提到构建LLM应用程序的步骤分解,可能涉及到代理平台的设计。引用[2]讨论了评估LLM的挑战,包括可重复性和开源模型的解决方案,这可能影响代理平台的稳定性和选择。引用[3]则提到大模型相关的岗位和面试题,可能涉及实际应用中的技术问题。 接下
recommend-type

Docker实现OAuth2代理:安全的HTTPS解决方案

### 知识点详细说明: #### Dockerfile基础 Dockerfile是一种文本文件,它包含了用户创建Docker镜像所需的命令和参数。Docker通过读取Dockerfile中的指令自动构建镜像。Dockerfile通常包含了如下载基础镜像、安装软件包、执行脚本等指令。 #### Dockerfile中的常用指令 1. **FROM**: 指定基础镜像,所有的Dockerfile都必须以FROM开始。 2. **RUN**: 在构建过程中执行命令,如安装软件。 3. **CMD**: 设置容器启动时运行的命令,可以被docker run命令后面的参数覆盖。 4. **EXPOSE**: 告诉Docker容器在运行时监听指定的网络端口。 5. **ENV**: 设置环境变量。 6. **ADD**: 将本地文件复制到容器中,如果是tar归档文件会自动解压。 7. **ENTRYPOINT**: 设置容器启动时的默认命令,不会被docker run命令覆盖。 8. **VOLUME**: 创建一个挂载点以挂载外部存储,如磁盘或网络文件系统。 #### OAuth 2.0 Proxy OAuth 2.0 Proxy 是一个轻量级的认证代理,用于在应用程序前提供OAuth认证功能。它主要通过HTTP重定向和回调机制,实现对下游服务的安全访问控制,支持多种身份提供商(IdP),如Google, GitHub等。 #### HTTPS和SSL/TLS HTTPS(HTTP Secure)是HTTP的安全版本,它通过SSL/TLS协议加密客户端和服务器之间的通信。使用HTTPS可以保护数据的机密性和完整性,防止数据在传输过程中被窃取或篡改。SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是用来在互联网上进行通信时加密数据的安全协议。 #### Docker容器与HTTPS 为了在使用Docker容器时启用HTTPS,需要在容器内配置SSL/TLS证书,并确保使用443端口。这通常涉及到配置Nginx或Apache等Web服务器,并将其作为反向代理运行在Docker容器内。 #### 临时分叉(Fork) 在开源领域,“分叉”指的是一种特殊的复制项目的行为,通常是为了对原项目进行修改或增强功能。分叉的项目可以独立于原项目发展,并可选择是否合并回原项目。在本文的语境下,“临时分叉”可能指的是为了实现特定功能(如HTTPS支持)而在现有Docker-oauth2-proxy项目基础上创建的分支版本。 #### 实现步骤 要实现HTTPS支持的docker-oauth2-proxy,可能需要进行以下步骤: 1. **准备SSL/TLS证书**:可以使用Let's Encrypt免费获取证书或自行生成。 2. **配置Nginx/Apache服务器**:在Dockerfile中添加配置,以使用SSL证书和代理设置。 3. **修改OAuth2 Proxy设置**:调整OAuth2 Proxy配置以使用HTTPS连接。 4. **分叉Docker-oauth2-proxy项目**:创建项目的分支副本,以便进行修改。 5. **编辑Dockerfile**:在分叉的项目中编写或修改Dockerfile,包括下载基础镜像、设置环境变量、添加SSL证书、配置Nginx/Apache和OAuth2 Proxy等步骤。 6. **构建和测试新镜像**:使用Docker构建镜像,并在安全环境中进行测试,确保HTTPS配置正确,并且OAuth2 Proxy功能正常工作。 7. **部署到生产环境**:在确认无误后,将配置好的镜像部署到生产环境中。 #### 压缩包子文件的文件名称列表 - **docker-oauth2-proxy-master**: 这可能是指在GitHub等代码托管平台上,docker-oauth2-proxy项目的主分支或主仓库。名称列表中的“master”暗示了该文件夹包含的是主分支的代码。 总结来说,要实现一个支持HTTPS的docker-oauth2-proxy,开发者需要进行一系列的配置和编码工作,包括使用Dockerfile来构建自定义的Docker镜像,配置SSL/TLS证书,分叉并修改现有的开源项目代码。通过这些步骤,可以确保OAuth2 Proxy能够安全地处理HTTPS请求,并为下游服务提供安全认证功能。
recommend-type

利用AmazonSageMaker进行图像分类:从理论到实践

# 利用 Amazon SageMaker 进行图像分类:从理论到实践 ## 1. 主题建模与图像分类概述 在数据科学领域,从大量非结构化数据中提取信息和主题至关重要。像 SageMaker 的神经主题模型(NTM)这类主题建模技术,提供了线性和非线性学习方法,能帮助我们深入挖掘数据中的潜在主题。它通过特定的架构和内部机制工作,还支持分布式训练,将数据集分割成多个块进行并行处理。训练完成后,我们可以将模型部署为端点并进行推理,例如解读安然邮件中的主题。 图像分类在过去五年中一直是热门研究领域,因为它能解决众多行业的实际业务问题,如自动驾驶汽车行业就高度依赖图像分类和目标检测模型的准确性。A
recommend-type

wed前端开发网页设计

<think>好的,用户需要寻找关于Web前端开发和网页设计的相关资源或教程。首先,我需要理解用户的具体需求,他们可能刚入门,想要系统学习,或者有一定基础,需要进阶教程。根据用户的问题,他们提到了“教程”和“资源”,可能希望推荐书籍、在线课程、框架文档以及社区论坛等。 接下来,我需要参考用户提供的引用内容。引用[1]提到了周文洁的《HTML5网页前端设计实战》,这是一本配套的实战项目教程,适合有基础的读者,可能可以作为书籍推荐之一。引用[2]概述了Web前端开发的技术分类,包括客户端和服务器端技术,以及常用框架如Bootstrap、React等。引用[3]是关于Delphi的TMS WEB
recommend-type

eosforce下的scatter API应用实例教程

### eosforce使用分散API #### 知识点一:什么是EOSForce EOSForce是以EOSIO为技术基础,旨在为区块链应用提供高性能的公链解决方案。它类似于EOS,也使用了EOSIO软件套件,开发者可以基于EOSIO构建DAPP应用,同时它可能拥有与EOS不同的社区治理结构和经济模型。对于开发者来说,了解EOSForce的API和功能是非常关键的,因为它直接影响到应用的开发与部署。 #### 知识点二:scatter API的介绍 scatter API 是一个开源的JavaScript库,它的目的是为了简化EOSIO区块链上各类操作,包括账户管理和交易签名等。scatter旨在提供一个更为便捷、安全的用户界面,通过API接口与EOSIO区块链进行交互。用户无需保存私钥即可与区块链进行交互,使得整个过程更加安全,同时开发者也能够利用scatter实现功能更加强大的应用。 #### 知识点三:scatter API在EOSForce上的应用 在EOSForce上使用scatter API可以简化开发者对于区块链交互的工作,无需直接处理复杂的私钥和签名问题。scatter API提供了一整套用于与区块链交互的方法,包括但不限于账户创建、身份验证、签名交易、数据读取等。通过scatter API,开发者可以更加专注于应用逻辑的实现,而不必担心底层的区块链交互细节。 #### 知识点四:安装和运行scatter_demo项目 scatter_demo是基于scatter API的一个示例项目,通过它可以学习如何将scatter集成到应用程序中。根据提供的描述,安装该项目需要使用npm,即Node.js的包管理器。首先需要执行`npm install`来安装依赖,这个过程中npm会下载scatter_demo项目所需的所有JavaScript包。安装完成后,可以通过运行`npm run dev`命令启动项目,该命令通常与项目中的开发环境配置文件(如webpack.config.js)相对应,用于启动本地开发服务器和热重载功能,以便开发者实时观察代码修改带来的效果。 #### 知识点五:配置eosforce到scatter 在scatter_demo项目中,将eosforce配置到scatter需要进入scatter的设置界面。scatter提供了一个可视化的界面,允许用户管理自己的区块链网络配置。在scatter设置中选择“网络”一栏,然后选择“新建”,在此步骤中需要选择“eos”作为区块链类型。之后,将eosforce的节点配置信息填入对应区域,完成网络的设置。这样,scatter就能够连接到eosforce区块链,用户可以通过scatter API与eosforce区块链进行交互。 #### 知识点六:npm包管理器及安装命令 npm是Node.js的包管理器,它在Node.js项目中扮演着至关重要的角色,用来安装、管理和分享项目所需的代码包。`npm install`是npm的常用命令,用于安装项目依赖。在执行此命令时,npm会根据项目根目录中的`package.json`文件自动下载并安装所需的所有依赖包。这个文件描述了项目的依赖关系,包括每个依赖的版本范围。通过这种方式,开发者可以确保项目在不同的环境中都能够有相同的行为表现。 #### 结论 了解和掌握如何在EOSForce中使用scatter API对于区块链应用开发者来说是极其重要的。scatter简化了与EOSIO区块链的交互过程,提高开发效率,降低了实现复杂功能的技术门槛。在实际操作中,开发者需要关注如何正确安装scatter_demo项目,如何配置eosforce节点到scatter中,以及如何利用scatter API开发出功能完善的区块链应用。通过这些知识点的了解,开发者可以更好地把握EOSForce生态中的开发实践,并在项目中实现安全、便捷的区块链交互。
recommend-type

AI模型评估与应用拓展

# AI模型评估与应用拓展 ## 1. 模型性能评估 ### 1.1 实验假设 我们有三个模型,假设第一个基于周一和周二点击数据训练的模型,在预测周四后期应用下载量方面,不如第二和第三个模型。第二个基于周一到周三点击数据训练的模型,性能也不如第三个基于周一到周四大部分时间点击数据训练的模型。 ### 1.2 特征重要性分析 以下代码用于分析每个模型中重要的特征: ```python exp_lst = ['exp1', 'exp2', 'exp3'] for exp in exp_lst: model_file = os.path.join(sm_output_loc, exp,
recommend-type

elasticsearch serverless

<think> 首先,用户要求了解 Elasticsearch Serverless 的相关信息,包括介绍、使用和优势等。参考的引用内容提供了背景信息,我需要基于这些引用进行回答。引用 [1] 到 [5] 提供了关键点。 关键引用内容: - [^1]: Elasticsearch Serverless 基于 Elasticsearch 的优势,满足现代工作负载的需求,如大数据集、AI 搜索和不可预测的流量。 - [^2]: Elasticsearch Serverless 是云端全托管的服务,基于云原生 Serverless 技术,提供自动弹性和免运维能力,解决资源成本问题,兼容 ELK 生