活动介绍

当list<B>和list<A>以多个字段进行匹配,且匹配到的件数比是N:M,将匹配成功的list<A>和list<B>出力。用java8写一段实现上述需求的共通方法

时间: 2024-05-14 16:15:04 浏览: 124
假设 A 和 B 类都有字段 a1 和 a2,用于匹配。 ``` public static void match(List<A> listA, List<B> listB) { Map<String, List<B>> bMap = listB.stream().collect(Collectors.groupingBy(b -> b.getA1() + b.getA2())); for (A a : listA) { List<B> matchList = bMap.get(a.getA1() + a.getA2()); if (matchList != null) { System.out.println("Matched A: " + a); System.out.println("Matched B: " + matchList); } } } ``` 首先将 listB 转换成 Map,以 a1 和 a2 的组合作为 key,每个 key 对应一个 B 对象的 List。然后遍历 listA,根据 a1 和 a2 的组合从 Map 中获取匹配的 B 对象的 List,如果不为 null,则输出匹配的 A 和 B 对象。
相关问题

<template> <div :class="prefixCls"> <div> <table style="width: 100%; margin: 10px auto 0 auto; border-collapse:collapse;"> <thead> <tr> <th colspan="12" style="padding: 10px;font-size:20px">常德芙蓉烟叶复烤有限责任公司</th> </tr> <tr> <th colspan="12" style="padding: 10px;font-size:18px">物资调拨承运结算单</th> </tr> <tr> <th colspan="9" style="padding: 10px 5px;"></th> <th colspan="1" style="padding: 10px 5px;">单据号:</th> <th colspan="2" style="padding: 10px 5px;text-align: left;">{{ rowData.splitNo }}</th> </tr> <tr> <th colspan="2" style="padding: 10px 5px;">发货仓库:</th> <th colspan="2" style="padding: 10px 5px;text-align: left;"><el-input v-if="isEditOut" v-model="this.orderData.dataList[0].outStoreName"></el-input><div v-else>{{ this.orderData.dataList[0].outStoreName }}</div></th> <th colspan="5" style="padding: 10px 5px;"></th> <th colspan="1" style="padding: 10px 5px;">记录编号:</th> <th colspan="2" style="padding: 10px 5px;text-align: left;">FRFK/YW/GL-05/03.0</th> </tr> <tr> <th colspan="2" style="padding: 10px 5px;">收货仓库:</th> <th colspan="2" style="padding: 10px 5px;text-align: left;">{{ this.orderData.dataList[0].inStoreName }}</th> <th colspan="5" style="padding: 10px 5px;">{{ time.format("YYYY年MM月DD日") }}</th> <th colspan="1" style="padding: 10px 5px;">单位:</th> <th colspan="2" style="padding: 10px 5px;text-align: left;">KG</th> </tr> </thead> <thead> <tr> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" rowspan="2">类 别</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" rowspan="2">品 种</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" rowspan="2">年 度</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" rowspan="2">产 地</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" rowspan="2">等 级</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" colspan="2">应发数</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" colspan="2">实发数</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" colspan="2">实收数</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;" rowspan="2">到货时间</th> </tr> <tr> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;">件数</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;">重量</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;">件数</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;">重量</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;">件数</th> <th style="padding: 10px 5px;border: 1px solid #000;text-align: center;">重量</th> </tr> </thead> <tbody> <tr v-for="(item, index) in orderData.dataList" :key="index"> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ item.category }}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ item.variety }}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ item.planYear }}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ item.placeOrigin }}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ item.gradeNo }}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ Math.ceil(item.amountKg/40)}}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;">{{ item.amountKg }}</td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;"><div v-if="showOut"><el-input v-if="isEditOut" v-model="item.realAmountPiece" ></el-input><div v-else>{{ item.realAmountPiece }}</div></div><div v-if="showIn">{{ item.realAmountPiece }}</div></td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;"><div v-if="showOut"><el-input v-if="isEditOut" v-model="item.realAmountKg" ></el-input><div v-else>{{ item.realAmountKg }}</div></div><div v-if="showIn">{{ item.realAmountKg }}</div></td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;"><div v-if="showIn"><el-input v-if="isEditIn" v-model="item.receiveAmountPiece" ></el-input><div v-else>{{item.receiveAmountPiece}}</div></div></td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;"><div v-if="showIn"><el-input v-if="isEditIn" v-model="item.receiveAmountKg" ></el-input><div v-else>{{item.receiveAmountKg}}</div></div></td> <td style="padding: 10px 5px;border: 1px solid #000;text-align: center;"><el-date-picker v-if="showIn" v-model="item.arrivedTime" type="datetime" placeholder="选择日期时间" format="yyyy-MM-dd " value-format="yyyy-MM-dd" value="time"></el-date-picker></td> </tr> <tr> <th colspan="1" style="padding: 10px 5px;border: 1px solid #000;">备注:</th> <th colspan="11" style="padding: 10px 5px;border: 1px solid #000;text-align: left;">{{ this.orderData.dataList[0].remark }}</th> </tr> </tbody> </table> <ul style="display: flex; flex-wrap: wrap; justify-content: space-between;font-weight: 700;"> <li style="width: 30%; margin: 10px 0 0px; list-style: none"> 制单:{{ this.orderData.dataList[0].createUserName }} </li> <li style="width: 30%; margin: 10px 0 0px; list-style: none"> 发货保管员: </li> <li style="width: 30%; margin: 10px 0 0px; list-style: none"> 汽车车号: </li> <li style="width: 30%; margin: 10px 0; list-style: none"> 承运司机: </li> <li style="width: 30%; margin: 10px 0; list-style: none"> 收货保管员: </li> <li style="width: 30%; margin: 10px 0; list-style: none"> </li> </ul> <ul style="display: flex; flex-wrap: wrap; justify-content: space-between;"> <li style="width: 25%; margin: 10px 0 0px; list-style: none"> 第一联:发货保管员 </li> <li style="width: 25%; margin: 10px 0 0px; list-style: none"> 第二联:运费结算凭证 </li> <li style="width: 25%; margin: 10px 0 0px; list-style: none"> 第三联:收货保管员 </li> <li style="width: 25%; margin: 10px 0; list-style: none"> 第四联:门卫 </li> </ul> </div> </div> </template> <script> import moment from 'moment' export default { name: "orderDetailPdf", props: { showOut: { type: Boolean, default: false, }, isEditOut: { type: Boolean, default: false, }, showIn: { type: Boolean, default: false, }, isEditIn: { type: Boolean, default: false, }, rowData: { type: Object, default: {}, } }, data() { return { prefixCls: "orderDetailPdf", row: {}, orderData: { dataList:[], }, orderStatus: { 10: "待付款", 20: "待审核", 30: "管理员取消", 35: "会员取消", 40: "审核不通过", 50: "审核通过", 80: "已回收", 90: "已完成", }, time: new Date(), }; }, created() {}, mounted() { if(this.rowData.splitItemId) { this.findItemData(this.rowData.splitItemId); } else if (this.rowData) { this.findItemData(this.rowData); } else { this.orderData.dataList = [{ category: "", variety: "", planYear: "", placeOrigin: "", gradeNo: "", amountKg: 0, realAmountPiece: 0, realAmountKg: 0, ReceiveAmountPiece: 0, ReceiveAmountKg: 0, outStoreName: "", inStoreName: "", remark: "", createUserName: "" }]; } this.time = moment(this.time); for (let i = 0; i < this.orderData.dataList.length; i++) { if(this.isEditIn){ this.orderData.dataList[i].receiveAmountPiece = this.orderData.dataList[i].realAmountPiece; this.orderData.dataList[i].receiveAmountKg = this.orderData.dataList[i].realAmountKg; } else if(this.isEditOut){ this.orderData.dataList[i].realAmountPiece = this.orderData.dataList[i].amountPiece; this.orderData.dataList[i].realAmountKg = this.orderData.dataList[i].amountKg; } } }, methods: { findItemData(id){ this.$axios({ method: "post", url: `${this.global.MSI_STORAGE}/splitAllot/findSplitAllotPrint`, data: { data:{ splitItemId: id } }, }).then((res) => { if (res.data.status === "Y") { this.orderData.dataList = [res.data.data]; } else { this.$message.error(res.data.message); this.orderData.dataList = [{ category: "", variety: "", planYear: "", placeOrigin: "", gradeNo: "", amountKg: 0, realAmountPiece: 0, realAmountKg: 0, ReceiveAmountPiece: 0, ReceiveAmountKg: 0, outStoreName: "", inStoreName: "", remark: "", createUserName: "" }]; } }); }, formatDateYMD (date) { if (!date) { return '' } return moment(date).format('YYYY-MM-DD') }, mathFormatter(num) { if (isNaN(parseFloat(num))) { return null; } var formatter = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); var n = formatter.format(num).replace(',', '') return n }, collectFormData() { return { splitItemId: this.orderData.dataList[0].splitItemId, realAmountPiece: this.orderData.dataList[0].realAmountPiece, realAmountKg: this.orderData.dataList[0].realAmountKg, receiveAmountPiece: this.orderData.dataList[0].receiveAmountPiece, receiveAmountKg: this.orderData.dataList[0].receiveAmountKg, arrivedTime: this.orderData.dataList[0].arrivedTime, outStoreName: this.orderData.dataList[0].outStoreName, }; } }, }; </script> <style lang="scss" scoped> $prefixCls: "orderDetailPdf"; .#{$prefixCls} { } </style>该vue中若isEditOut为真,则表示为出库编辑,此时item.realAmountKg表格项为输入,且其默认值需为item.amount,在mounted的for循环中欲实现此功能,但是失败了,怎么实现

<think>我们正在处理一个Vue组件中的需求:根据`isEditOut`状态,设置`item.realAmountKg`的默认值为`item.amountKg`,并在表格中显示为可编辑的输入框。 思路: 1. 在表格中,我们需要根据`isEditOut`的值来决定显示文本还是输入框。 2. 当`isEditOut`为真时,显示一个输入框,并且将输入框的值绑定到`item.realAmountKg`;当`isEditOut`为假时,显示`item.realAmountKg`(或者可能是`item.amountKg`,但根据需求,我们设置默认值后,应该显示`realAmountKg`)。 3. 关于设置默认值:我们需要在某个时机(比如数据初始化时,或者当`isEditOut`状态改变时)将`item.realAmountKg`设置为`item.amountKg`。注意,如果`item.realAmountKg`已经存在值(比如之前编辑过),我们可能不希望覆盖它,所以设置默认值的逻辑应该是:如果`realAmountKg`不存在或者需要重置时,才设置为`amountKg`。 实现方案: 方案1:在初始化数据时,或者在获取到数据后,遍历数据项,为每个item添加`realAmountKg`属性,如果`realAmountKg`不存在,则设置为`amountKg`的值。 方案2:在模板中,我们可以使用计算属性或者方法,但是考虑到实时性,我们可以在渲染时动态决定,但这样可能会导致无法正确绑定(因为需要可编辑,所以需要绑定到数据的一个属性上)。因此,更推荐在数据层面处理。 步骤: 1. 在数据获取后,我们遍历数组,为每个对象设置`realAmountKg`属性(如果还没有设置的话)。 2. 在表格的列中,使用`v-if`和`v-else`来切换显示输入框和文本。 示例代码: 假设我们的数据是通过一个数组`tableData`来存储的,每个元素是一个`item`对象。 在获取数据后(比如在`mounted`或者`created`钩子中,或者从API获取数据后),我们进行初始化: ```javascript // 假设这是从API获取的数据 this.tableData = response.data.map(item => { // 如果item没有realAmountKg属性,则设置默认值为amountKg if (item.realAmountKg === undefined || item.realAmountKg === null) { // 使用Vue的set确保响应性 this.$set(item, 'realAmountKg', item.amountKg); } return item; }); ``` 或者,我们可以在数据中本身就包含`realAmountKg`,那么就不需要处理。但如果不包含,我们需要设置。 在表格中,我们可以这样写: ```html <template v-for="(item, index) in tableData"> <!-- 其他列省略 --> <td> <template v-if="isEditOut"> <input type="text" v-model="item.realAmountKg" /> </template> <template v-else> {{ item.realAmountKg }} </template> </td> </template> ``` 但是,注意:如果`isEditOut`状态是全局的(比如整个表格的编辑状态),那么我们可以这样用。如果每个item有自己的编辑状态,那么可能需要一个字段来控制。 根据需求,我们有一个全局的`isEditOut`状态,所以可以这样。 然而,我们可能需要在`isEditOut`状态改变时,重置`realAmountKg`为`amountKg`?需求是设置默认值,但通常默认值只在初始化时设置一次。如果需求是每次进入编辑状态时,都将`realAmountKg`重置为`amountKg`,那么我们需要在`isEditOut`变为true的时候,遍历所有项并重置。 但是,注意:重置可能会覆盖用户已经编辑过的值。所以,需求可能是在进入编辑状态时,如果之前没有编辑过(即`realAmountKg`没有被修改过),则重置为`amountKg`。但这样就需要记录初始状态,比较复杂。 根据问题描述,我们只需要在设置时给默认值,所以我们可以这样:在初始化数据时设置一次,之后编辑状态改变时不再重置,除非有明确要求。 因此,我们只需要在数据初始化时设置默认值即可。 如果需求是每次切换到编辑状态时,都要重置为`amountKg`,那么我们可以这样做: 在`isEditOut`变为true的时候,遍历数组,将每个`item.realAmountKg`设置为`item.amountKg`(注意,这样会覆盖已有的编辑)。 所以,我们需要明确需求。根据问题描述:“设置默认值”,通常是在初始化时。所以这里我们按照初始化时设置默认值。 但是,如果数据是动态加载的,那么每次加载新数据时都需要设置。 总结步骤: 1. 在获取数据后,为每个item设置`realAmountKg`(如果该属性不存在,则设置为`amountKg`的值)。 2. 在表格中,根据`isEditOut`的值显示输入框或文本。 注意:使用`v-model`绑定输入框,这样用户输入的值会自动更新到`item.realAmountKg`。 另外,如果表格中还有其他列需要编辑,也可以使用同样的方式。 下面是一个完整的Vue组件的示例代码: ```vue <template> <div> <table> <thead> <tr> <th>其他列</th> <th>重量(kg)</th> </tr> </thead> <tbody> <tr v-for="(item, index) in tableData" :key="index"> <td>其他数据</td> <td> <input v-if="isEditOut" type="text" v-model="item.realAmountKg" /> <span v-else>{{ item.realAmountKg }}</span> </td> </tr> </tbody> </table> </div> </template> <script> export default { data() { return { isEditOut: false, // 初始状态为不可编辑 tableData: [] // 初始数据为空 }; }, created() { // 假设我们有一个方法获取数据 this.fetchData(); }, methods: { fetchData() { // 模拟从API获取数据 // 假设返回的数据结构为: { data: [ { amountKg: 100, ... }, ... ] } const response = { data: [{ amountKg: 100 }, { amountKg: 200 }] }; this.tableData = response.data.map(item => { // 如果item没有realAmountKg属性,则设置默认值为amountKg // 注意:这里我们使用Vue.set来确保新属性是响应式的 if (item.realAmountKg === undefined || item.realAmountKg === null) { // 这里我们直接给item添加属性,因为Vue无法检测到普通对象的新增属性,所以使用$set this.$set(item, 'realAmountKg', item.amountKg); } return item; }); } } }; </script> ``` 注意:在`fetchData`方法中,我们使用了`this.$set`来设置`realAmountKg`属性,这样Vue才能监听到这个属性的变化。因为直接给对象添加新属性不是响应式的。 另外,如果`isEditOut`状态需要切换,我们可以通过一个按钮或者外部事件来改变,然后表格就会相应地显示输入框或文本。 如果需求是每次切换到编辑状态时,都要将`realAmountKg`重置为`amountKg`(即覆盖之前的编辑),那么我们可以添加一个监听`isEditOut`的watch: ```javascript watch: { isEditOut(newVal) { if (newVal) { // 进入编辑状态,重置所有realAmountKg为amountKg this.tableData.forEach(item => { item.realAmountKg = item.amountKg; }); } } } ``` 但是,这个重置会覆盖用户之前编辑的值,所以是否这样做取决于业务需求。 如果需求是每次进入编辑状态时,如果用户没有编辑过(即realAmountKg没有被修改过),则重置,那么我们需要记录初始值。这可能会复杂一些,我们可以考虑在数据中存储一个原始值,然后在编辑时使用原始值重置。或者,在进入编辑状态时,先保存当前值,然后提供一个重置按钮等。 由于问题中没有明确要求,我们这里按照初始化设置默认值,不自动重置。 因此,最终代码如上所示。 相关问题: 1. 在Vue中,如何动态设置对象的属性并保持响应式? 2. Vue中如何根据条件切换输入框和文本显示? 3. 在Vue中,如何监听状态变化并执行数据重置操作?</think>### 在Vue组件中实现可编辑表格字段 在Vue组件中实现根据`isEditOut`状态设置`item.realAmountKg`默认值并使其可编辑,可以通过以下步骤实现: #### 1. 数据初始化与默认值设置 ```vue <script> export default { data() { return { tableData: [], // 表格数据 isEditOut: false // 编辑状态控制 } }, watch: { // 当编辑状态变化时设置默认值 isEditOut(newVal) { if (newVal) { this.tableData.forEach(item => { // 仅在realAmountKg未设置时使用amountKg作为默认值 if (item.realAmountKg === null || item.realAmountKg === undefined) { this.$set(item, 'realAmountKg', item.amountKg) } }) } } } } </script> ``` #### 2. 表格模板实现 ```vue <template> <table> <tr v-for="(item, index) in tableData" :key="index"> <!-- 其他列... --> <td> <template v-if="isEditOut"> <!-- 可编辑输入框 --> <input v-model="item.realAmountKg" type="number" @blur="validateInput(item)" > </template> <template v-else> <!-- 只读显示 --> {{ item.realAmountKg || item.amountKg }} </template> </td> </tr> </table> </template> ``` #### 3. 输入验证(可选) ```javascript methods: { validateInput(item) { // 确保输入有效值 if (isNaN(item.realAmountKg) || item.realAmountKg < 0) { this.$set(item, 'realAmountKg', item.amountKg) } } } ``` ### 关键实现说明 1. **响应式数据设置** 使用`this.$set()`确保新添加的`realAmountKg`属性是响应式的,避免直接赋值导致的响应性丢失问题[^1]。 2. **条件渲染逻辑** 通过`v-if="isEditOut"`控制输入框的显示,非编辑状态显示静态文本。 3. **默认值策略** 仅在`realAmountKg`未定义时使用`amountKg`作为默认值,保留用户已编辑的值。 4. **输入验证** 添加简单的数值验证,确保输入值的有效性。 ### 优化建议 1. 使用计算属性处理默认值逻辑: ```javascript computed: { processedData() { return this.tableData.map(item => ({ ...item, realAmountKg: item.realAmountKg ?? item.amountKg })) } } ``` 2. 对于复杂表格,建议使用专门的表格组件(如Element UI的el-table): ```vue <el-table-column prop="amount"> <template #default="{ row }"> <el-input v-if="isEditOut" v-model.number="row.realAmountKg" /> <span v-else>{{ row.realAmountKg || row.amountKg }}</span> </template> </el-table-column> ``` 3. 添加编辑状态指示器: ```vue <input v-model="item.realAmountKg" :class="{ 'editing': isEditOut }" > <style> .editing { border: 1px solid #409EFF; background-color: #f5f7fa; } </style> ```

List<PatentResultListVO> filteredList 有字段 /** * 已评估件数 */ private Long evaluatedCount; /** * 维持件数 */ private Long maintainCount; /** * 维持费用 */ private BigDecimal maintainCosts; /** * 放弃件数 */ private Long giveUpCount; /** * 放弃费用 */ private BigDecimal giveUpCosts; 计算总计,然后放在list的第一位

你希望将 `List<PatentResultListVO>` 中的某些字段进行 **总计计算**(如 `evaluatedCount`、`maintainCount`、`maintainCosts`、`giveUpCount`、`giveUpCosts`),并将计算结果作为新的 `PatentResultListVO` 对象插入到列表的 **第一位**。 --- ### ✅ 解决方案 你可以使用 Java Stream 对列表进行遍历并汇总字段值,然后构造一个汇总对象插入到列表头部。 --- ### ✅ Java 实现代码如下: ```java import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; public class PatentSummaryUtil { public static List<PatentResultListVO> addSummaryToFirst(List<PatentResultListVO> list) { if (list == null || list.isEmpty()) { return list; } // 初始化汇总对象 PatentResultListVO summary = new PatentResultListVO(); summary.setEvaluatedCount(list.stream().map(PatentResultListVO::getEvaluatedCount).filter(Objects::nonNull).mapToLong(Long::longValue).sum()); summary.setMaintainCount(list.stream().map(PatentResultListVO::getMaintainCount).filter(Objects::nonNull).mapToLong(Long::longValue).sum()); summary.setGiveUpCount(list.stream().map(PatentResultListVO::getGiveUpCount).filter(Objects::nonNull).mapToLong(Long::longValue).sum()); // BigDecimal 需要手动累加 BigDecimal maintainCostsSum = BigDecimal.ZERO; for (PatentResultListVO vo : list) { if (vo.getMaintainCosts() != null) { maintainCostsSum = maintainCostsSum.add(vo.getMaintainCosts()); } } summary.setMaintainCosts(maintainCostsSum); BigDecimal giveUpCostsSum = BigDecimal.ZERO; for (PatentResultListVO vo : list) { if (vo.getGiveUpCosts() != null) { giveUpCostsSum = giveUpCostsSum.add(vo.getGiveUpCosts()); } } summary.setGiveUpCosts(giveUpCostsSum); // 设置汇总项的其他字段(可选) summary.setDept("总计"); // 示例字段,用于标识 // 插入到列表第一位 List<PatentResultListVO> result = new ArrayList<>(); result.add(summary); result.addAll(list); return result; } } ``` --- ### ✅ VO 类定义示例: ```java import java.math.BigDecimal; public class PatentResultListVO { private String dept; private Long evaluatedCount; private Long maintainCount; private BigDecimal maintainCosts; private Long giveUpCount; private BigDecimal giveUpCosts; // Getters and Setters } ``` --- ### ✅ 使用示例: ```java List<PatentResultListVO> resultListVOS = ...; // 初始化你的列表数据 List<PatentResultListVO> listWithSummary = PatentSummaryUtil.addSummaryToFirst(resultListVOS); ``` --- ### ✅ 说明: - 使用 Java Stream 对 `Long` 类型字段进行累加。 - `BigDecimal` 不支持 `mapToDouble`,需要手动累加。 - 汇总对象设置 `"总计"` 字段用于标识这是汇总行。 - 最终返回的新列表中,汇总对象位于第一位。 ---
阅读全文

相关推荐

def get_5_workdays_back(end_date=None): """计算从结束日期倒推5个工作日的起始日期""" end_date = pd.Timestamp.now().normalize() if end_date is None else end_date count = 0 current_date = end_date # 复用原有节假日配置 holidays = [ # 元旦(不调休) '2025-01-01', # 周三 # 春节(调休2天) '2025-01-28', '2025-01-29', '2025-01-30', '2025-01-31', '2025-02-01', '2025-02-02', '2025-02-03', '2025-02-04', # 1.28(除夕)-2.4 # 清明节(不调休) '2025-04-04', '2025-04-05', '2025-04-06', # 周五-周日 # 劳动节(调休1天) '2025-05-01', '2025-05-02', '2025-05-03', '2025-05-04', '2025-05-05', # 周四-周一 # 端午节(不调休) '2025-05-31', '2025-06-01', '2025-06-02', # 周六-周一 # 中秋节+国庆节(调休2天) '2025-10-01', '2025-10-02', '2025-10-03', '2025-10-04', '2025-10-05', '2025-10-06', '2025-10-07', '2025-10-08' # 周三-下周三 ] holiday_dates = pd.to_datetime(holidays) # 新增调休工作日列表(转换为日期格式) workdays_adjustment = [ '2025-01-26', # 周日补春节 '2025-02-08', # 周六补春节 '2025-04-27', # 周日补劳动节 '2025-09-28', # 周日补国庆 '2025-10-11' # 周六补国庆 ] adjustment_dates = pd.to_datetime(workdays_adjustment) # 转换日期格式 while count < 5: current_date -= pd.Timedelta(days=1) # 判断是否为有效工作日 is_workday = ( (current_date.weekday() < 5 or current_date in adjustment_dates) and current_date not in holiday_dates ) if is_workday: count += 1 return current_date, end_date # 获取处理后的数据 df = getchaoshi() # 计算时间范围 start_date, end_date = get_5_workdays_back() date_mask = (df['收案时间'] >= start_date) & (df['收案时间'] <= end_date) weekly_cases = df[date_mask].copy() # 计算上周时间范围 last_week_start, _ = get_5_workdays_back(start_date) date_mask_last_week = (df['收案时间'] >= last_week_start) & (df['收案时间'] < start_date) last_weekly_cases = df[date_mask_last_week].copy() last_week_stats = last_weekly_cases.groupby('组别')['案件状态'].count().reset_index() last_week_stats.columns = ['组别', '上周总案件数'] # 新增:统计上周已完成案件(根据结案时间) date_mask_last_week_closed = (df['结案时间'] >= last_week_start) & (df['结案时间'] < start_date) last_week_closed_cases = df[date_mask_last_week_closed].copy() # 分组统计上周已完成数据 last_week_closed_stats = last_week_closed_cases.groupby('组别')['案件状态'].count().reset_index() last_week_closed_stats.columns = ['组别', '上周已完成情况'] # 添加状态分类列 weekly_cases['状态分类'] = weekly_cases['案件状态'].apply( lambda x: '已完成' if x in ['办结', '发件'] else '正在处理' ) # 分组统计 result = weekly_cases.groupby('组别').agg( 总案件数=('案件状态', 'count'), 已完成=('状态分类', lambda x: (x == '已完成').sum()), 处理中=('状态分类', lambda x: (x == '正在处理').sum()), 超时案件数=('是否超时', lambda x: (x == '是').sum()), 缓办案件数=('是否缓办', lambda x: (x == '是').sum()) # 新增行 ).reset_index() result = result.merge(last_week_stats, on='组别', how='left') result = result.merge(last_week_closed_stats, on='组别', how='left').fillna(0) total_row = { '组别': '总计', '总案件数': result['总案件数'].sum(), '已完成': result['已完成'].sum(), '处理中': result['处理中'].sum(), '超时案件数': result['超时案件数'].sum(), '缓办案件数': result['缓办案件数'].sum(), '上周总案件数': result['上周总案件数'].sum(), '上周已完成情况': result['上周已完成情况'].sum() # 新增列 } result = pd.concat([result, pd.DataFrame([total_row])], ignore_index=True) # 创建只含首行时间的列表 query_time = pd.Timestamp.now().strftime("%Y-%m-%d %H:%M") query_time_list = [query_time] + ['']*(len(result)-1) # 例如:['2025-05-20 14:30', '', '', ''] # 插入不重复的列 result.insert(0, '查询时间', query_time_list) # 只有首行有值 # 创建Excel写入对象(注意:需要安装openpyxl) with ExcelWriter('GCB案件统计结果t4.xlsx', engine='openpyxl') as writer: # 将result写入Sheet1 result.to_excel(writer, sheet_name='按周统计情况', index=False) worksheet = writer.sheets['按周统计情况'] # 合并A2到An单元格(n=数据总行数) worksheet.merge_cells( start_row=2, end_row=len(result) + 1, # +1补偿标题行偏移 start_column=1, end_column=1 )weekly_cases中,字段“是否超时”,结果为是,输出到新的sheet,命名为本周超时案件

def get_5_workdays_back(end_date=None): """计算从结束日期倒推5个工作日的起始日期""" end_date = pd.Timestamp.now().normalize() if end_date is None else end_date count = 0 current_date = end_date # 复用原有节假日配置 holidays = [ # 元旦(不调休) '2025-01-01', # 周三 # 春节(调休2天) '2025-01-28', '2025-01-29', '2025-01-30', '2025-01-31', '2025-02-01', '2025-02-02', '2025-02-03', '2025-02-04', # 1.28(除夕)-2.4 # 清明节(不调休) '2025-04-04', '2025-04-05', '2025-04-06', # 周五-周日 # 劳动节(调休1天) '2025-05-01', '2025-05-02', '2025-05-03', '2025-05-04', '2025-05-05', # 周四-周一 # 端午节(不调休) '2025-05-31', '2025-06-01', '2025-06-02', # 周六-周一 # 中秋节+国庆节(调休2天) '2025-10-01', '2025-10-02', '2025-10-03', '2025-10-04', '2025-10-05', '2025-10-06', '2025-10-07', '2025-10-08' # 周三-下周三 ] holiday_dates = pd.to_datetime(holidays) # 新增调休工作日列表(转换为日期格式) workdays_adjustment = [ '2025-01-26', # 周日补春节 '2025-02-08', # 周六补春节 '2025-04-27', # 周日补劳动节 '2025-09-28', # 周日补国庆 '2025-10-11' # 周六补国庆 ] adjustment_dates = pd.to_datetime(workdays_adjustment) # 转换日期格式 while count < 5: current_date -= pd.Timedelta(days=1) # 判断是否为有效工作日 is_workday = ( (current_date.weekday() < 5 or current_date in adjustment_dates) and current_date not in holiday_dates ) if is_workday: count += 1 return current_date, end_date # 获取处理后的数据 df = getchaoshi() # 计算时间范围 start_date, end_date = get_5_workdays_back() date_mask = (df['收案时间'] >= start_date) & (df['收案时间'] <= end_date) weekly_cases = df[date_mask].copy() # 计算上周时间范围 last_week_start, _ = get_5_workdays_back(start_date) date_mask_last_week = (df['收案时间'] >= last_week_start) & (df['收案时间'] < start_date) last_weekly_cases = df[date_mask_last_week].copy() last_week_stats = last_weekly_cases.groupby('组别')['案件状态'].count().reset_index() last_week_stats.columns = ['组别', '上周总案件数'] # 新增:统计上周已完成案件(根据结案时间) date_mask_last_week_closed = (df['结案时间'] >= last_week_start) & (df['结案时间'] < start_date) last_week_closed_cases = df[date_mask_last_week_closed].copy() # 分组统计上周已完成数据 last_week_closed_stats = last_week_closed_cases.groupby('组别')['案件状态'].count().reset_index() last_week_closed_stats.columns = ['组别', '上周已完成情况'] # 添加状态分类列 weekly_cases['状态分类'] = weekly_cases['案件状态'].apply( lambda x: '已完成' if x in ['办结', '发件'] else '正在处理' ) # 分组统计 result = weekly_cases.groupby('组别').agg( 总案件数=('案件状态', 'count'), 已完成=('状态分类', lambda x: (x == '已完成').sum()), 处理中=('状态分类', lambda x: (x == '正在处理').sum()), 超时案件数=('是否超时', lambda x: (x == '是').sum()), 缓办案件数=('是否缓办', lambda x: (x == '是').sum()) # 新增行 ).reset_index() result = result.merge(last_week_stats, on='组别', how='left') result = result.merge(last_week_closed_stats, on='组别', how='left').fillna(0) total_row = { '组别': '总计', '总案件数': result['总案件数'].sum(), '已完成': result['已完成'].sum(), '处理中': result['处理中'].sum(), '超时案件数': result['超时案件数'].sum(), '缓办案件数': result['缓办案件数'].sum(), '上周总案件数': result['上周总案件数'].sum(), '上周已完成情况': result['上周已完成情况'].sum() # 新增列 } result = pd.concat([result, pd.DataFrame([total_row])], ignore_index=True) # 创建只含首行时间的列表 query_time = pd.Timestamp.now().strftime("%Y-%m-%d %H:%M") query_time_list = [query_time] + ['']*(len(result)-1) # 例如:['2025-05-20 14:30', '', '', ''] # 插入不重复的列 result.insert(0, '查询时间', query_time_list) # 只有首行有值 # 创建Excel写入对象(注意:需要安装openpyxl) with ExcelWriter('GCB案件统计结果t4.xlsx', engine='openpyxl') as writer: # 将result写入Sheet1 result.to_excel(writer, sheet_name='按周统计情况', index=False) worksheet = writer.sheets['按周统计情况'] # 合并A2到An单元格(n=数据总行数) worksheet.merge_cells( start_row=2, end_row=len(result) + 1, # +1补偿标题行偏移 start_column=1, end_column=1 )输出的按周统计情况,不显示上周总案件数和上周已完成情况这两列

商品信息表tb_product_info id product_id shop_id tag in_price quantity release_time 1 8001 901 日用 60 1000 2020-01-01 10:00:00 2 8002 901 零食 140 500 2020-01-01 10:00:00 3 8003 901 零食 160 500 2020-01-01 10:00:00 4 8004 902 零食 130 500 2020-01-01 10:00:00 (product_id-商品ID, shop_id-店铺ID, tag-商品类别标签, in_price-进货价格, quantity-进货数量, release_time-上架时间) 订单总表tb_order_overall id order_id uid event_time total_amount total_cnt status 1 301002 102 2021-10-01 11:00:00 235 2 1 2 301003 101 2021-10-02 10:00:00 300 2 1 3 301005 104 2021-10-03 10:00:00 160 1 1 (order_id-订单号, uid-用户ID, event_time-下单时间, total_amount-订单总金额, total_cnt-订单商品总件数, status-订单状态) 订单明细表tb_order_detail id order_id product_id price cnt 1 301002 8001 85 1 2 301002 8003 180 1 3 301003 8004 140 1 4 301003 8003 180 1 5 301005 8003 180 1 (order_id-订单号, product_id-商品ID, price-商品单价, cnt-下单数量) 问题:请计算2021年10月商城里所有新用户的首单平均交易金额(客单价)和平均获客成本(保留一位小数)。 注:订单的优惠金额 = 订单明细里的{该订单各商品单价×数量之和} - 订单总表里的{订单总金额} 。 输出示例: 示例数据的输出结果如下 avg_amount avg_cost 231.7 23.3 解释: 2021年10月有3个新用户,102的首单为301002,订单金额为235,商品总金额为85+180=265,优惠金额为30; 101的首单为301003,订单金额为300,商品总金额为140+180=320,优惠金额为20; 104的首单为301005,订单金额为160,商品总金额为180,优惠金额为20; 平均首单客单价为(235+300+160)/3=231.7,平均获客成本为(30+20+20)/3=23.3 题目如上所示,为什么我的代码:select ROUND(amount/num,1) avg_amount, ROUND(sum(cost-amount)/num,1) avg_cost from( select sum(price*cnt) cost, avg(total_amount) amount, count(distinct uid) num from tb_order_overall join tb_order_detail using(order_id) where date_format(event_time,‘%Y%m’)=‘202110’ group by uid )t 运行结果程序异常退出, 请检查代码"是否有数组越界等异常"或者"是否有语法错误" SQL_ERROR_INFO: “In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column ‘t.amount’; this is incompatible with sql_mode=only_full_group_by”

pdf
内容概要:文章详细介绍了ETL工程师这一职业,解释了ETL(Extract-Transform-Load)的概念及其在数据处理中的重要性。ETL工程师负责将分散、不统一的数据整合为有价值的信息,支持企业的决策分析。日常工作包括数据整合、存储管理、挖掘设计支持和多维分析展现。文中强调了ETL工程师所需的核心技能,如数据库知识、ETL工具使用、编程能力、业务理解能力和问题解决能力。此外,还盘点了常见的ETL工具,包括开源工具如Kettle、XXL-JOB、Oozie、Azkaban和海豚调度,以及企业级工具如TASKCTL和Moia Comtrol。最后,文章探讨了ETL工程师的职业发展路径,从初级到高级的技术晋升,以及向大数据工程师或数据产品经理的横向发展,并提供了学习资源和求职技巧。 适合人群:对数据处理感兴趣,尤其是希望从事数据工程领域的人士,如数据分析师、数据科学家、软件工程师等。 使用场景及目标:①了解ETL工程师的职责和技能要求;②选择适合自己的ETL工具;③规划ETL工程师的职业发展路径;④获取相关的学习资源和求职建议。 其他说明:随着大数据技术的发展和企业数字化转型的加速,ETL工程师的需求不断增加,尤其是在金融、零售、制造、人工智能、物联网和区块链等领域。数据隐私保护法规的完善也使得ETL工程师在数据安全和合规处理方面的作用更加重要。

最新推荐

recommend-type

PLC控制变频器:三菱与汇川PLC通过485通讯板实现变频器正反转及调速控制

内容概要:本文介绍了如何利用三菱和汇川PLC通过485通讯板实现变频器的正转、反转及调速控制。主要内容涵盖硬件配置、软件编程、具体控制逻辑及上机测试。文中详细描述了各个步骤的操作方法和注意事项,包括关键寄存器的设置及其含义。程序中有详细的中文注释,便于理解和维护。最终通过上机测试验证系统的稳定性和可靠性。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉PLC编程和变频器控制的专业人士。 使用场景及目标:适用于需要对电机进行精确控制的工业应用场景,如生产线、机械设备等。目标是提高控制系统灵活性和效率,确保系统稳定可靠。 其他说明:本文不仅提供理论指导,还附带实际操作经验,有助于读者更好地掌握相关技术和应用。
recommend-type

Python桌面版数独(五版)-优化选择模式触发新棋盘生成

Python桌面版数独(五版)-优化选择模式触发新棋盘生成
recommend-type

jmeter 下载使用5.6.3

jmeter 下载使用5.6.3
recommend-type

数据工程ETL工程师全解析:从数据抽取到加载的技术要点与职业发展路径

内容概要:文章详细介绍了ETL工程师这一职业,解释了ETL(Extract-Transform-Load)的概念及其在数据处理中的重要性。ETL工程师负责将分散、不统一的数据整合为有价值的信息,支持企业的决策分析。日常工作包括数据整合、存储管理、挖掘设计支持和多维分析展现。文中强调了ETL工程师所需的核心技能,如数据库知识、ETL工具使用、编程能力、业务理解能力和问题解决能力。此外,还盘点了常见的ETL工具,包括开源工具如Kettle、XXL-JOB、Oozie、Azkaban和海豚调度,以及企业级工具如TASKCTL和Moia Comtrol。最后,文章探讨了ETL工程师的职业发展路径,从初级到高级的技术晋升,以及向大数据工程师或数据产品经理的横向发展,并提供了学习资源和求职技巧。 适合人群:对数据处理感兴趣,尤其是希望从事数据工程领域的人士,如数据分析师、数据科学家、软件工程师等。 使用场景及目标:①了解ETL工程师的职责和技能要求;②选择适合自己的ETL工具;③规划ETL工程师的职业发展路径;④获取相关的学习资源和求职建议。 其他说明:随着大数据技术的发展和企业数字化转型的加速,ETL工程师的需求不断增加,尤其是在金融、零售、制造、人工智能、物联网和区块链等领域。数据隐私保护法规的完善也使得ETL工程师在数据安全和合规处理方面的作用更加重要。
recommend-type

基于51单片机的嵌入式系统开发_DS18B20温度传感器_LCD1602显示_I2C通信_24C02存储_Proteus仿真_Keil开发_温度监测与智能调控系统_包含温度上下限设.zip

基于51单片机的嵌入式系统开发_DS18B20温度传感器_LCD1602显示_I2C通信_24C02存储_Proteus仿真_Keil开发_温度监测与智能调控系统_包含温度上下限设.zip
recommend-type

Web前端开发:CSS与HTML设计模式深入解析

《Pro CSS and HTML Design Patterns》是一本专注于Web前端设计模式的书籍,特别针对CSS(层叠样式表)和HTML(超文本标记语言)的高级应用进行了深入探讨。这本书籍属于Pro系列,旨在为专业Web开发人员提供实用的设计模式和实践指南,帮助他们构建高效、美观且可维护的网站和应用程序。 在介绍这本书的知识点之前,我们首先需要了解CSS和HTML的基础知识,以及它们在Web开发中的重要性。 HTML是用于创建网页和Web应用程序的标准标记语言。它允许开发者通过一系列的标签来定义网页的结构和内容,如段落、标题、链接、图片等。HTML5作为最新版本,不仅增强了网页的表现力,还引入了更多新的特性,例如视频和音频的内置支持、绘图API、离线存储等。 CSS是用于描述HTML文档的表现(即布局、颜色、字体等样式)的样式表语言。它能够让开发者将内容的表现从结构中分离出来,使得网页设计更加模块化和易于维护。随着Web技术的发展,CSS也经历了多个版本的更新,引入了如Flexbox、Grid布局、过渡、动画以及Sass和Less等预处理器技术。 现在让我们来详细探讨《Pro CSS and HTML Design Patterns》中可能包含的知识点: 1. CSS基础和选择器: 书中可能会涵盖CSS基本概念,如盒模型、边距、填充、边框、背景和定位等。同时还会介绍CSS选择器的高级用法,例如属性选择器、伪类选择器、伪元素选择器以及选择器的组合使用。 2. CSS布局技术: 布局是网页设计中的核心部分。本书可能会详细讲解各种CSS布局技术,包括传统的浮动(Floats)布局、定位(Positioning)布局,以及最新的布局模式如Flexbox和CSS Grid。此外,也会介绍响应式设计的媒体查询、视口(Viewport)单位等。 3. 高级CSS技巧: 这些技巧可能包括动画和过渡效果,以及如何优化性能和兼容性。例如,CSS3动画、关键帧动画、转换(Transforms)、滤镜(Filters)和混合模式(Blend Modes)。 4. HTML5特性: 书中可能会深入探讨HTML5的新标签和语义化元素,如`<article>`、`<section>`、`<nav>`等,以及如何使用它们来构建更加标准化和语义化的页面结构。还会涉及到Web表单的新特性,比如表单验证、新的输入类型等。 5. 可访问性(Accessibility): Web可访问性越来越受到重视。本书可能会介绍如何通过HTML和CSS来提升网站的无障碍访问性,比如使用ARIA标签(Accessible Rich Internet Applications)来增强屏幕阅读器的使用体验。 6. 前端性能优化: 性能优化是任何Web项目成功的关键。本书可能会涵盖如何通过优化CSS和HTML来提升网站的加载速度和运行效率。内容可能包括代码压缩、合并、避免重绘和回流、使用Web字体的最佳实践等。 7. JavaScript与CSS/HTML的交互: 在现代Web开发中,JavaScript与CSS及HTML的交云并用是不可或缺的。书中可能会讲解如何通过JavaScript动态地修改样式、操作DOM元素以及使用事件监听和响应用户交互。 8. Web框架和预处理器: 这本书可能会提到流行的Web开发框架和预处理器,比如Bootstrap、Foundation、Sass和Less等,它们是如何简化和加速开发流程的。 9. 测试和维护: 书中也可能包含关于如何测试网页以及如何持续优化和维护CSS和HTML代码的章节。例如,使用断言测试、自动化测试、性能分析工具等。 最后,鉴于文件名称列表中的“压缩包子文件”的表述,这可能是对“压缩包”文件的一种误译或误用,此处“压缩包”应该指的是包含该书籍PDF文件的压缩文件格式,如ZIP或RAR。而“Pro CSS and HTML Design Patterns.pdf”指的就是该书籍的PDF格式电子版文件。 以上所述,构成了《Pro CSS and HTML Design Patterns》一书可能包含的核心知识点。通过学习这些内容,Web前端开发者可以掌握更为高效和优雅的设计模式,从而在日常工作中更高效地解决实际问题。
recommend-type

Zotero 7数据同步:Attanger插件安装&设置,打造文献管理利器

/i.s3.glbimg.com/v1/AUTH_08fbf48bc0524877943fe86e43087e7a/internal_photos/bs/2018/L/j/ipKA8TRPyt4ptaG1DGww/t-m-01.png) # 1. Zotero 7数据同步简介 在数字时代,管理研究数据变得日益重要,而Zot
recommend-type

卷积神经网络的基础理论200字

<think>我们正在回答用户关于卷积神经网络(CNN)基础理论的询问。根据提供的引用资料,我们可以概述CNN的基本结构和工作原理。引用[1]提到CNN是一种前馈神经网络,信息从输入单向流动到输出。引用[2]指出CNN在图像处理等领域应用广泛,通过层次结构和参数调整实现模式识别。引用[3]说明CNN包含卷积层,使用卷积核提取局部特征,减少参数量,提高效率。引用[4]则提到了训练过程,包括前向传播、误差计算和反向传播(梯度下降)。因此,我们将从以下几个方面概述CNN:1.CNN的基本结构(卷积层、池化层、全连接层)2.卷积操作的工作原理(局部感受野、权重共享)3.训练过程(前向传播、损失函数、反
recommend-type

轻便实用的Java库类查询工具介绍

标题 "java2库类查询" 和描述表明,所提及的工具是一个专门用于查询Java库类的应用程序。此软件旨在帮助开发者快速地查找和引用Java的标准开发工具包(SDK)中包含的所有应用程序编程接口(API)类。通过这样的工具,开发者可以节省大量在官方文档或搜索引擎上寻找类定义和使用方法的时间。它被描述为轻巧且方便,这表明其占用的系统资源相对较少,同时提供直观的用户界面,使得查询过程简洁高效。 从描述中可以得出几个关键知识点: 1. Java SDK:Java的软件开发工具包(SDK)是Java平台的一部分,提供了一套用于开发Java应用软件的软件包和库。这些软件包通常被称为API,为开发者提供了编程界面,使他们能够使用Java语言编写各种类型的应用程序。 2. 库类查询:这个功能对于开发者来说非常关键,因为它提供了一个快速查找特定库类及其相关方法、属性和使用示例的途径。良好的库类查询工具可以帮助开发者提高工作效率,减少因查找文档而中断编程思路的时间。 3. 轻巧性:软件的轻巧性通常意味着它对计算机资源的要求较低。这样的特性对于资源受限的系统尤为重要,比如老旧的计算机、嵌入式设备或是当开发者希望最小化其开发环境占用空间时。 4. 方便性:软件的方便性通常关联于其用户界面设计,一个直观、易用的界面可以让用户快速上手,并减少在使用过程中遇到的障碍。 5. 包含所有API:一个优秀的Java库类查询软件应当能够覆盖Java所有标准API,这包括Java.lang、Java.util、Java.io等核心包,以及Java SE平台的所有其他标准扩展包。 从标签 "java 库 查询 类" 可知,这个软件紧密关联于Java编程语言的核心功能——库类的管理和查询。这些标签可以关联到以下知识点: - Java:一种广泛用于企业级应用、移动应用(如Android应用)、网站后端、大型系统和许多其他平台的编程语言。 - 库:在Java中,库是一组预打包的类和接口,它们可以被应用程序重复使用。Java提供了庞大的标准库,以支持各种常见的任务和功能。 - 查询:查询指的是利用软件工具搜索、定位和检索信息的过程。对于Java库类查询工具来说,这意味着可以通过类名、方法签名或其他标识符来查找特定的API条目。 最后,压缩包文件列表包含了两个文件:“java.dit”和“Java.exe”。其中“Java.exe”很可能是程序的可执行文件,而“java.dit”可能是一个数据文件,用于存储Java类的索引或数据。由于文件名后缀通常与文件类型相关联,但“dit”并不是一个常见的文件扩展名。这可能是一个特定于软件的自定义格式,或是一个打字错误。 总结来说,"java2库类查询" 是一个针对Java开发者的实用工具,它提供了一个轻量级、易用的平台来查询和定位Java标准库中的所有类和API。此工具对优化开发流程,减少查找Java类文档的时间大有裨益,尤其适合需要频繁查阅Java API的开发者使用。
recommend-type

【Zotero 7终极指南】:新手必备!Attanger插件全攻略与数据同步神技

# 1. Zotero 7与Attanger插件的介绍 在当今的学术研究和知识管理领域,高效的文献管理工具至关重要。Zotero 7作为一个流行的参考文献管理软件,因其强大的功能和用户友好的界面而受到专业人士的青睐。而Attanger插件则为Zotero 7带来了更多定制化和高级功能,极大地增强