feat: add material search filters to semi, product, service modules
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
This commit is contained in:
@ -114,3 +114,15 @@ def get_user_suggestions():
|
|||||||
keyword = request.args.get('keyword', '')
|
keyword = request.args.get('keyword', '')
|
||||||
data = ProductInboundService.search_system_users(keyword)
|
data = ProductInboundService.search_system_users(keyword)
|
||||||
return jsonify({"code": 200, "msg": "success", "data": data})
|
return jsonify({"code": 200, "msg": "success", "data": data})
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# 7. 获取筛选选项
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@inbound_product_bp.route('/options', methods=['GET'])
|
||||||
|
def get_options():
|
||||||
|
try:
|
||||||
|
data = ProductInboundService.get_filter_options()
|
||||||
|
return jsonify({"code": 200, "msg": "success", "data": data})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"code": 500, "msg": str(e)}), 500
|
||||||
|
|||||||
@ -128,3 +128,15 @@ def get_user_suggestions():
|
|||||||
keyword = request.args.get('keyword', '')
|
keyword = request.args.get('keyword', '')
|
||||||
data = SemiInboundService.search_system_users(keyword)
|
data = SemiInboundService.search_system_users(keyword)
|
||||||
return jsonify({"code": 200, "msg": "success", "data": data})
|
return jsonify({"code": 200, "msg": "success", "data": data})
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# 7. 获取筛选选项
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@inbound_semi_bp.route('/options', methods=['GET'])
|
||||||
|
def get_options():
|
||||||
|
try:
|
||||||
|
data = SemiInboundService.get_filter_options()
|
||||||
|
return jsonify({"code": 200, "msg": "success", "data": data})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"code": 500, "msg": str(e)}), 500
|
||||||
|
|||||||
@ -162,3 +162,16 @@ def get_user_suggestions():
|
|||||||
keyword = request.args.get('keyword', '')
|
keyword = request.args.get('keyword', '')
|
||||||
data = ServiceService.search_system_users(keyword)
|
data = ServiceService.search_system_users(keyword)
|
||||||
return jsonify({'code': 200, 'msg': 'success', 'data': data})
|
return jsonify({'code': 200, 'msg': 'success', 'data': data})
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
# 获取筛选选项
|
||||||
|
# ------------------------------------------------------------------
|
||||||
|
@inbound_bp.route('/service/options', methods=['GET'])
|
||||||
|
@jwt_required()
|
||||||
|
def get_options():
|
||||||
|
try:
|
||||||
|
data = ServiceService.get_filter_options()
|
||||||
|
return jsonify({'code': 200, 'msg': 'success', 'data': data})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'code': 500, 'msg': str(e)}), 500
|
||||||
|
|||||||
@ -280,7 +280,7 @@ class ProductInboundService:
|
|||||||
# 6. 获取列表
|
# 6. 获取列表
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_list(page, limit, keyword=None, statuses=None):
|
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None):
|
||||||
from app.models.inbound.product import StockProduct
|
from app.models.inbound.product import StockProduct
|
||||||
try:
|
try:
|
||||||
query = db.session.query(StockProduct).outerjoin(MaterialBase, StockProduct.base_id == MaterialBase.id)
|
query = db.session.query(StockProduct).outerjoin(MaterialBase, StockProduct.base_id == MaterialBase.id)
|
||||||
@ -295,6 +295,13 @@ class ProductInboundService:
|
|||||||
StockProduct.sku.ilike(f'%{keyword}%')
|
StockProduct.sku.ilike(f'%{keyword}%')
|
||||||
))
|
))
|
||||||
|
|
||||||
|
# 类别筛选
|
||||||
|
if category and category.strip():
|
||||||
|
query = query.filter(MaterialBase.category == category.strip())
|
||||||
|
# 类型筛选
|
||||||
|
if material_type and material_type.strip():
|
||||||
|
query = query.filter(MaterialBase.material_type == material_type.strip())
|
||||||
|
|
||||||
if not statuses:
|
if not statuses:
|
||||||
statuses = ['在库', '借库']
|
statuses = ['在库', '借库']
|
||||||
|
|
||||||
@ -377,3 +384,25 @@ class ProductInboundService:
|
|||||||
return users
|
return users
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 8. 获取筛选选项(类别、类型)
|
||||||
|
# ============================================================
|
||||||
|
@staticmethod
|
||||||
|
def get_filter_options():
|
||||||
|
try:
|
||||||
|
from app.models.base import MaterialBase
|
||||||
|
categories = db.session.query(MaterialBase.category) \
|
||||||
|
.filter(MaterialBase.category != None, MaterialBase.category != '') \
|
||||||
|
.distinct().all()
|
||||||
|
types = db.session.query(MaterialBase.material_type) \
|
||||||
|
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
|
||||||
|
.distinct().all()
|
||||||
|
return {
|
||||||
|
"categories": [r[0] for r in categories],
|
||||||
|
"types": [r[0] for r in types]
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"categories": [], "types": []}
|
||||||
|
|||||||
@ -378,7 +378,7 @@ class SemiInboundService:
|
|||||||
# 6. 获取列表
|
# 6. 获取列表
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_list(page, limit, keyword=None, statuses=None):
|
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None):
|
||||||
from app.models.inbound.semi import StockSemi
|
from app.models.inbound.semi import StockSemi
|
||||||
try:
|
try:
|
||||||
query = db.session.query(StockSemi).outerjoin(MaterialBase, StockSemi.base_id == MaterialBase.id)
|
query = db.session.query(StockSemi).outerjoin(MaterialBase, StockSemi.base_id == MaterialBase.id)
|
||||||
@ -397,6 +397,13 @@ class SemiInboundService:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 类别筛选
|
||||||
|
if category and category.strip():
|
||||||
|
query = query.filter(MaterialBase.category == category.strip())
|
||||||
|
# 类型筛选
|
||||||
|
if material_type and material_type.strip():
|
||||||
|
query = query.filter(MaterialBase.material_type == material_type.strip())
|
||||||
|
|
||||||
if not statuses:
|
if not statuses:
|
||||||
statuses = ['在库', '借库']
|
statuses = ['在库', '借库']
|
||||||
|
|
||||||
@ -479,3 +486,25 @@ class SemiInboundService:
|
|||||||
return users
|
return users
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 8. 获取筛选选项(类别、类型)
|
||||||
|
# ============================================================
|
||||||
|
@staticmethod
|
||||||
|
def get_filter_options():
|
||||||
|
try:
|
||||||
|
from app.models.base import MaterialBase
|
||||||
|
categories = db.session.query(MaterialBase.category) \
|
||||||
|
.filter(MaterialBase.category != None, MaterialBase.category != '') \
|
||||||
|
.distinct().all()
|
||||||
|
types = db.session.query(MaterialBase.material_type) \
|
||||||
|
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
|
||||||
|
.distinct().all()
|
||||||
|
return {
|
||||||
|
"categories": [r[0] for r in categories],
|
||||||
|
"types": [r[0] for r in types]
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"categories": [], "types": []}
|
||||||
|
|||||||
@ -204,3 +204,25 @@ class ServiceService:
|
|||||||
return users
|
return users
|
||||||
except Exception:
|
except Exception:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 获取筛选选项(类别、类型)
|
||||||
|
# ============================================================
|
||||||
|
@classmethod
|
||||||
|
def get_filter_options(cls):
|
||||||
|
try:
|
||||||
|
from app.models.base import MaterialBase
|
||||||
|
categories = db.session.query(MaterialBase.category) \
|
||||||
|
.filter(MaterialBase.category != None, MaterialBase.category != '') \
|
||||||
|
.distinct().all()
|
||||||
|
types = db.session.query(MaterialBase.material_type) \
|
||||||
|
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
|
||||||
|
.distinct().all()
|
||||||
|
return {
|
||||||
|
"categories": [r[0] for r in categories],
|
||||||
|
"types": [r[0] for r in types]
|
||||||
|
}
|
||||||
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return {"categories": [], "types": []}
|
||||||
|
|||||||
@ -49,3 +49,11 @@ export function getUserSuggestions(params: any) {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 筛选选项
|
||||||
|
export function getFilterOptions() {
|
||||||
|
return request({
|
||||||
|
url: '/inbound/product/options',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -52,3 +52,11 @@ export function getUserSuggestions(params: any) {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 筛选选项
|
||||||
|
export function getFilterOptions() {
|
||||||
|
return request({
|
||||||
|
url: '/inbound/semi/options',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -122,6 +122,14 @@ export function getUserSuggestions(params: any) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 筛选选项
|
||||||
|
export function getFilterOptions() {
|
||||||
|
return request({
|
||||||
|
url: '/v1/inbound/service/options',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 删除服务权益
|
// 删除服务权益
|
||||||
export function deleteService(id: number) {
|
export function deleteService(id: number) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
@ -1,21 +1,36 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="semi-module">
|
<div class="semi-module">
|
||||||
<div class="header-tools">
|
<div class="header-tools">
|
||||||
<div class="left-tools">
|
<div class="left-tools" style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="queryParams.keyword"
|
v-model="queryParams.keyword"
|
||||||
placeholder="🔍 搜索物料 / 批号 / SN / 工单号 / BOM..."
|
placeholder="请输入名称或规格"
|
||||||
class="search-input"
|
|
||||||
clearable
|
clearable
|
||||||
@clear="fetchData"
|
|
||||||
@keyup.enter="fetchData"
|
@keyup.enter="fetchData"
|
||||||
style="width: 300px; margin-right: 10px;"
|
style="width: 240px;"
|
||||||
|
/>
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.category"
|
||||||
|
placeholder="类别"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
@change="fetchData"
|
||||||
|
style="width: 160px;"
|
||||||
>
|
>
|
||||||
<template #append>
|
<el-option v-for="item in categoryOptions" :key="item" :label="item" :value="item" />
|
||||||
<el-button :icon="Search" @click="fetchData"/>
|
</el-select>
|
||||||
</template>
|
<el-select
|
||||||
</el-input>
|
v-model="queryParams.material_type"
|
||||||
|
placeholder="类型"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
@change="fetchData"
|
||||||
|
style="width: 160px;"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in typeOptions" :key="item" :label="item" :value="item" />
|
||||||
|
</el-select>
|
||||||
|
<el-button type="primary" plain @click="fetchData">搜索</el-button>
|
||||||
|
<el-button @click="resetQuery">重置</el-button>
|
||||||
<el-select
|
<el-select
|
||||||
v-model="queryParams.statuses"
|
v-model="queryParams.statuses"
|
||||||
multiple
|
multiple
|
||||||
@ -453,7 +468,9 @@ const dialogStatus = ref<'create' | 'update'>('create')
|
|||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const queryParams = reactive({ page: 1, pageSize: 15, keyword: '', statuses: ['在库', '借库'] })
|
const queryParams = reactive({ page: 1, pageSize: 15, keyword: '', category: '', material_type: '', statuses: ['在库', '借库'] })
|
||||||
|
const categoryOptions = ref<string[]>([])
|
||||||
|
const typeOptions = ref<string[]>([])
|
||||||
const materialOptions = ref<any[]>([])
|
const materialOptions = ref<any[]>([])
|
||||||
|
|
||||||
// 打印相关变量
|
// 打印相关变量
|
||||||
@ -625,6 +642,26 @@ const fetchData = async () => {
|
|||||||
} finally { loading.value = false }
|
} finally { loading.value = false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetchOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res: any = await getFilterOptions()
|
||||||
|
if (res.code === 200) {
|
||||||
|
categoryOptions.value = res.data.categories
|
||||||
|
typeOptions.value = res.data.types
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fetch options failed', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryParams.keyword = ''
|
||||||
|
queryParams.category = ''
|
||||||
|
queryParams.material_type = ''
|
||||||
|
queryParams.page = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
dialogStatus.value = 'create'
|
dialogStatus.value = 'create'
|
||||||
resetForm()
|
resetForm()
|
||||||
@ -780,7 +817,10 @@ const getStatusType = (status: string) => { const map: any = { '在库': 'succes
|
|||||||
const getQualityType = (status: string) => { const map: any = { '合格': 'success', '不合格': 'danger', '待检': 'info', '返修中': 'warning' }; return map[status] || 'info' }
|
const getQualityType = (status: string) => { const map: any = { '合格': 'success', '不合格': 'danger', '待检': 'info', '返修中': 'warning' }; return map[status] || 'info' }
|
||||||
const formatMoney = (val: any) => { const num = Number(val); return isNaN(num) ? '-' : `¥ ${num.toFixed(2)}` }
|
const formatMoney = (val: any) => { const num = Number(val); return isNaN(num) ? '-' : `¥ ${num.toFixed(2)}` }
|
||||||
|
|
||||||
onMounted(() => fetchData())
|
onMounted(() => {
|
||||||
|
fetchData()
|
||||||
|
fetchOptions()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user