Compare commits
2 Commits
9406669f1c
...
682139bab8
| Author | SHA1 | Date | |
|---|---|---|---|
| 682139bab8 | |||
| e564c5a5d2 |
@ -12,7 +12,9 @@ import traceback
|
||||
import json
|
||||
import io
|
||||
import datetime
|
||||
import numpy as np
|
||||
from app.utils.ai_vision import extract_and_embed
|
||||
from app.services.image_embedding_service import ImageEmbeddingService
|
||||
# 需要 pip install openpyxl
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
|
||||
@ -556,10 +558,15 @@ class MaterialBaseService:
|
||||
product_image=json.dumps(data.get('generalImage', [])),
|
||||
is_enabled=is_enabled_val
|
||||
)
|
||||
# 实时提取产品图向量(失败不影响业务)
|
||||
if new_material.product_image:
|
||||
new_material.img_embedding = extract_and_embed(new_material.product_image)
|
||||
db.session.add(new_material)
|
||||
db.session.flush() # 获取 new_material.id
|
||||
|
||||
# 提取产品图向量到独立表(失败不影响业务)
|
||||
image_list = data.get('generalImage', [])
|
||||
if isinstance(image_list, list) and image_list:
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_MATERIAL_BASE, new_material.id, image_list
|
||||
)
|
||||
db.session.commit()
|
||||
return new_material
|
||||
|
||||
@ -588,11 +595,17 @@ class MaterialBaseService:
|
||||
if 'generalManual' in data:
|
||||
material.manual_link = json.dumps(data['generalManual'])
|
||||
if 'generalImage' in data:
|
||||
material.product_image = json.dumps(data['generalImage'])
|
||||
|
||||
# 补上这两行:提取新上传图片的向量!
|
||||
if material.product_image:
|
||||
material.img_embedding = extract_and_embed(material.product_image)
|
||||
new_photo_list = data['generalImage']
|
||||
material.product_image = json.dumps(new_photo_list)
|
||||
# 保存向量到独立表(全量替换)
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_MATERIAL_BASE, material.id, new_photo_list
|
||||
)
|
||||
else:
|
||||
material.product_image = None
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_MATERIAL_BASE, material.id
|
||||
)
|
||||
|
||||
# 【核心修改】:兼容前端传来的布尔值
|
||||
if 'isEnabled' in data:
|
||||
@ -659,6 +672,10 @@ class MaterialBaseService:
|
||||
f"请先清理相关库存或仅‘禁用’此条目。"
|
||||
)
|
||||
|
||||
# 删除时同步清理向量记录
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_MATERIAL_BASE, material.id
|
||||
)
|
||||
db.session.delete(material)
|
||||
db.session.commit()
|
||||
return material_name
|
||||
|
||||
@ -9,7 +9,9 @@ from sqlalchemy import or_, func, text, and_
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
import traceback
|
||||
import json
|
||||
import numpy as np
|
||||
from app.utils.ai_vision import extract_and_embed
|
||||
from app.services.image_embedding_service import ImageEmbeddingService
|
||||
|
||||
|
||||
class BuyInboundService:
|
||||
@ -178,10 +180,15 @@ class BuyInboundService:
|
||||
arrival_photo=json.dumps(data.get('arrival_photo', [])),
|
||||
inspection_report=json.dumps(data.get('inspection_report', []))
|
||||
)
|
||||
# 实时提取到货图片向量(失败不影响业务)
|
||||
if new_stock.arrival_photo:
|
||||
new_stock.arrival_image_embedding = extract_and_embed(new_stock.arrival_photo)
|
||||
db.session.add(new_stock)
|
||||
db.session.flush() # 获取 new_stock.id
|
||||
|
||||
# 提取到货图片向量到新表(失败不影响业务)
|
||||
photo_list = data.get('arrival_photo', [])
|
||||
if isinstance(photo_list, list) and photo_list:
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_BUY, new_stock.id, photo_list
|
||||
)
|
||||
db.session.commit()
|
||||
return new_stock
|
||||
except Exception as e:
|
||||
@ -244,9 +251,19 @@ class BuyInboundService:
|
||||
for k, v in field_mapping.items():
|
||||
if k in data: setattr(stock, v, data[k])
|
||||
|
||||
if 'arrival_photo' in data: stock.arrival_photo = json.dumps(data['arrival_photo'])
|
||||
if 'arrival_photo' in data and stock.arrival_photo:
|
||||
stock.arrival_image_embedding = extract_and_embed(stock.arrival_photo)
|
||||
if 'arrival_photo' in data:
|
||||
new_photo_list = data['arrival_photo']
|
||||
stock.arrival_photo = json.dumps(new_photo_list)
|
||||
# 保存向量到独立表(全量替换)
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_BUY, stock.id, new_photo_list
|
||||
)
|
||||
else:
|
||||
stock.arrival_photo = None
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_BUY, stock.id
|
||||
)
|
||||
|
||||
if 'inspection_report' in data: stock.inspection_report = json.dumps(data['inspection_report'])
|
||||
|
||||
# 更新税率
|
||||
@ -289,8 +306,11 @@ class BuyInboundService:
|
||||
try:
|
||||
stock = StockBuy.query.get(stock_id)
|
||||
if not stock: raise ValueError("记录不存在")
|
||||
# 提前获取物料名称用于审计日志(通过外键关系 base.name 获取)
|
||||
material_name = stock.base.name if stock.base else '未知物料'
|
||||
# 删除时同步清理向量记录
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_BUY, stock.id
|
||||
)
|
||||
db.session.delete(stock)
|
||||
db.session.commit()
|
||||
return material_name
|
||||
|
||||
@ -9,7 +9,9 @@ from sqlalchemy import or_, func, text, and_
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
import traceback
|
||||
import json
|
||||
import numpy as np
|
||||
from app.utils.ai_vision import extract_and_embed
|
||||
from app.services.image_embedding_service import ImageEmbeddingService
|
||||
|
||||
|
||||
class ProductInboundService:
|
||||
@ -184,10 +186,14 @@ class ProductInboundService:
|
||||
sale_price=float(data.get('sale_price') or 0),
|
||||
order_id=data.get('order_id')
|
||||
)
|
||||
# 实时提取成品实拍图向量(失败不影响业务)
|
||||
if new_stock.product_photo:
|
||||
new_stock.arrival_image_embedding = extract_and_embed(new_stock.product_photo)
|
||||
db.session.add(new_stock)
|
||||
db.session.flush() # 获取 new_stock.id
|
||||
|
||||
# 提取产品图片向量到独立表(失败不影响业务)
|
||||
if isinstance(photo_list, list) and photo_list:
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_PRODUCT, new_stock.id, photo_list
|
||||
)
|
||||
db.session.commit()
|
||||
return new_stock
|
||||
except Exception as e:
|
||||
@ -217,10 +223,17 @@ class ProductInboundService:
|
||||
if f in data: setattr(stock, f, data[f])
|
||||
|
||||
if 'product_photo' in data:
|
||||
imgs = data['product_photo']
|
||||
if isinstance(imgs, list): stock.product_photo = json.dumps(imgs)
|
||||
if stock.product_photo:
|
||||
stock.arrival_image_embedding = extract_and_embed(stock.product_photo)
|
||||
new_photo_list = data['product_photo']
|
||||
stock.product_photo = json.dumps(new_photo_list)
|
||||
# 保存向量到独立表(全量替换)
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_PRODUCT, stock.id, new_photo_list
|
||||
)
|
||||
else:
|
||||
stock.product_photo = None
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_PRODUCT, stock.id
|
||||
)
|
||||
if 'quality_report_link' in data:
|
||||
imgs = data['quality_report_link']
|
||||
if isinstance(imgs, list): stock.quality_report_link = json.dumps(imgs)
|
||||
@ -261,8 +274,11 @@ class ProductInboundService:
|
||||
try:
|
||||
stock = StockProduct.query.get(stock_id)
|
||||
if stock:
|
||||
# 提前获取物料名称用于审计日志(通过外键关系 base.name 获取)
|
||||
material_name = stock.base.name if stock.base else '未知物料'
|
||||
# 删除时同步清理向量记录
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_PRODUCT, stock.id
|
||||
)
|
||||
db.session.delete(stock)
|
||||
db.session.commit()
|
||||
return material_name
|
||||
|
||||
@ -9,7 +9,9 @@ from sqlalchemy import or_, func, text, and_
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
import traceback
|
||||
import json
|
||||
import numpy as np
|
||||
from app.utils.ai_vision import extract_and_embed
|
||||
from app.services.image_embedding_service import ImageEmbeddingService
|
||||
|
||||
|
||||
class SemiInboundService:
|
||||
@ -221,10 +223,14 @@ class SemiInboundService:
|
||||
detail_link=data.get('detail_link'),
|
||||
remark=data.get('remark')
|
||||
)
|
||||
# 实时提取到货图片向量(失败不影响业务)
|
||||
if new_stock.arrival_photo:
|
||||
new_stock.arrival_image_embedding = extract_and_embed(new_stock.arrival_photo)
|
||||
db.session.add(new_stock)
|
||||
db.session.flush() # 获取 new_stock.id
|
||||
|
||||
# 提取到货图片向量到独立表(失败不影响业务)
|
||||
if isinstance(arrival_list, list) and arrival_list:
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_SEMI, new_stock.id, arrival_list
|
||||
)
|
||||
db.session.commit()
|
||||
return new_stock
|
||||
except Exception as e:
|
||||
@ -272,11 +278,17 @@ class SemiInboundService:
|
||||
setattr(stock, db_attr, data[frontend_key])
|
||||
|
||||
if 'arrival_photo' in data:
|
||||
imgs = data['arrival_photo']
|
||||
if isinstance(imgs, list):
|
||||
stock.arrival_photo = json.dumps(imgs)
|
||||
if stock.arrival_photo:
|
||||
stock.arrival_image_embedding = extract_and_embed(stock.arrival_photo)
|
||||
new_photo_list = data['arrival_photo']
|
||||
stock.arrival_photo = json.dumps(new_photo_list)
|
||||
# 保存向量到独立表(全量替换)
|
||||
ImageEmbeddingService.save_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_SEMI, stock.id, new_photo_list
|
||||
)
|
||||
else:
|
||||
stock.arrival_photo = None
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_SEMI, stock.id
|
||||
)
|
||||
if 'quality_report_link' in data:
|
||||
imgs = data['quality_report_link']
|
||||
if isinstance(imgs, list):
|
||||
@ -350,8 +362,11 @@ class SemiInboundService:
|
||||
stock = StockSemi.query.get(stock_id)
|
||||
if not stock:
|
||||
raise ValueError("记录不存在")
|
||||
# 提前获取物料名称用于审计日志(通过外键关系 base.name 获取)
|
||||
material_name = stock.base.name if stock.base else '未知物料'
|
||||
# 删除时同步清理向量记录
|
||||
ImageEmbeddingService.delete_embeddings(
|
||||
ImageEmbeddingService.MODULE_STOCK_SEMI, stock.id
|
||||
)
|
||||
db.session.delete(stock)
|
||||
db.session.commit()
|
||||
return material_name
|
||||
|
||||
@ -239,7 +239,7 @@ const handleLogout = () => {
|
||||
<footer v-if="!isLoginPage" class="app-footer">
|
||||
<span class="version-tag">
|
||||
<el-icon style="vertical-align: middle; margin-right: 4px"><InfoFilled /></el-icon>
|
||||
当前版本:V3.33(识图版)
|
||||
当前版本:V3.34(识图版)
|
||||
</span>
|
||||
</footer>
|
||||
|
||||
|
||||
@ -642,7 +642,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, nextTick, computed } from 'vue';
|
||||
import { ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
|
||||
import { Plus, Document, Refresh, Setting, Rank, Camera, Link, Download, Bell, CircleCheck, Files, ZoomIn, Delete, Picture } from '@element-plus/icons-vue';
|
||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
@ -1736,17 +1736,27 @@ const resetAdvancedFilter = () => {
|
||||
getList();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// 1. 修复背景联动:直接对 reactive 对象赋值
|
||||
if (route.query.keyword) {
|
||||
queryParams.keyword = route.query.keyword as string;
|
||||
queryParams.searchField = 'all';
|
||||
}
|
||||
// 以图搜图跳转:监听路由 keyword 参数,自动搜索并清理 URL
|
||||
watch(
|
||||
() => route.query.keyword,
|
||||
(newKeyword) => {
|
||||
if (newKeyword) {
|
||||
queryParams.keyword = newKeyword as string;
|
||||
queryParams.searchField = 'all';
|
||||
getList();
|
||||
// 清理 URL 参数,防止刷新后重复触发搜索
|
||||
router.replace({ path: route.path, query: {} });
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 先根据权限初始化列显示状态
|
||||
onMounted(() => {
|
||||
initColumnPermissions();
|
||||
// 此时 getList 会带着正确的 keyword 向后端请求过滤后的数据
|
||||
getList();
|
||||
// 无外部 keyword 参数时执行默认查询;有 keyword 则由上方的 watch 接管
|
||||
if (!route.query.keyword) {
|
||||
getList();
|
||||
}
|
||||
getOptionsList();
|
||||
|
||||
// 2. 修复弹窗锁定逻辑
|
||||
|
||||
Reference in New Issue
Block a user