#111 Advanced Search Form

复杂搜索构建
本文介绍了一种使用Rails构建高级搜索功能的方法,通过POST请求而非GET请求处理包含多个字段的复杂搜索表单,展示了如何创建Search资源并自定义搜索条件。
If you need to create an advanced search with a lot of fields, it may not be ideal to use a GET request as I showed in episode 37. In this episode I will show you how to handle this by creating a Search resource.
<!-- views/searches/new.html.erb -->
<% form_for @search do |f| %>
<p>
<%= f.label :keywords %><br />
<%= f.text_field :keywords %>
</p>
<p>
<%= f.label :category_id %><br />
<%= f.collection_select :category_id, Category.all, :id, :name, :include_blank => true %>
</p>
<p>
Price Range<br />
<%= f.text_field :minimum_price, :size => 7 %> -
<%= f.text_field :maximum_price, :size => 7 %>
</p>
<p><%= f.submit "Submit" %></p>
<% end %>

# models/search.rb
def products
@products ||= find_products
end

private

def find_products
Product.find(:all, :conditions => conditions)
end

def keyword_conditions
["products.name LIKE ?", "%#{keywords}%"] unless keywords.blank?
end

def minimum_price_conditions
["products.price >= ?", minimum_price] unless minimum_price.blank?
end

def maximum_price_conditions
["products.price <= ?", maximum_price] unless maximum_price.blank?
end

def category_conditions
["products.category_id = ?", category_id] unless category_id.blank?
end

def conditions
[conditions_clauses.join(' AND '), *conditions_options]
end

def conditions_clauses
conditions_parts.map { |condition| condition.first }
end

def conditions_options
conditions_parts.map { |condition| condition[1..-1] }.flatten
end

def conditions_parts
private_methods(false).grep(/_conditions$/).map { |m| send(m) }.compact
end
<template> <div v-loading="loading" class="content"> <div class="title"> <div class="text"> {{ $t(&#39;产品模型&#39;) }} </div> <div class="date"> <DatePicker ref="datePicker" @changeDate="changeDate"></DatePicker> </div> </div> <MyCard class="data_list"> <MoreSearch :defaultTip="$t(&#39;名称搜索&#39;)" :defaultExpandForm="true" @expandMore="expandMore" @enterSearch="enterSearch" > <template #btnList> <el-row type="flex"> <el-col :span="24"> <el-button v-preventReClick type="primary" @click="add"> {{ $t(&#39;Add&#39;) }} </el-button> </el-col> </el-row> </template> </MoreSearch> <SearchForm v-show="showForm" ref="formModel" type="Virtual_Model_List_Config" @changeSearch="getSearchForm" ></SearchForm> <UserTable ref="userTable" class="table_data" type="Virtual_Model_List_Config" :tableData="tableData" :needIndex="true" :needAction="true" :needExpand="true" :tableWidth="tableWidth" :fixeds="fixeds" :needShowImg="[&#39;sync_status&#39;]" :imgAddress="imgAddress" :dictionTypes="[&#39;Virtual_Model_List_Config&#39;]" :dynamicSlotName="[&#39;name_cn&#39;, &#39;action&#39;]" > <template #expand="props"> <TreeTableLoad ref="treeTableLoad" class="table_expand" instanceType="model" :instanceId="props.row.id" :hasAction="true" :Wstyles="true" citype="Virtual_Bom_Instance_Info_Head" :propsRow="props.row" :tableExpand="true" ></TreeTableLoad> </template> <template #name_cn="props"> <el-button class="btn_link_select" link @click="viewLog(props.row)"> {{ props.row.name_cn }} </el-button> </template> <template #action="props"> <el-button link @click="edit(props.row)"> {{ $t(&#39;Edit&#39;) }} </el-button> <el-button link @click="syncData(props.row)"> {{ $t(&#39;sync&#39;) }} </el-button> <el-button link @click="deleteData(props.row)"> {{ $t(&#39;delete&#39;) }} </el-button> </template> </UserTable> <Pagination ref="Pagination" :total="total" @onChange="tableChange" /> </MyCard> <el-dialog v-model="showDialog" class="dialog" :title="$t(&#39;delete&#39;)" width="30%"> <div> <el-input v-model.trim="textareas" type="textarea" maxlength="500" :rows="2" :autosize="{ minRows: 2, maxRows: 4 }" :placeholder="applyLang(&#39;请输入&#39;, &#39;Please enter&#39;)" show-word-limit ></el-input> </div> <template #footer> <div class="dialog_footer"> <el-button v-preventReClick type="primary" @click="submit"> {{ $t(&#39;确定&#39;) }} </el-button> <el-button v-preventReClick @click="closeDialog"> {{ $t(&#39;Cancels&#39;) }} </el-button> </div> </template> </el-dialog> <el-dialog v-model="addTypeDialog" :title="$t(&#39;新增类型&#39;)" width="20%"> <div class="add_dialog"> <el-button @click="addModel(&#39;ILaunch&#39;)"> {{ $t(&#39;iLaunch模型&#39;) }} </el-button> <el-button @click="addModel(&#39;PDM&#39;)"> {{ $t(&#39;PDM模型&#39;) }} </el-button> </div> </el-dialog> </div> </template> <script> import MyCard from &#39;../components/MyCard.vue&#39;; import UserTable from &#39;../supplyData/userTable.vue&#39;; import Pagination from &#39;../components/Pagination.vue&#39;; import DatePicker from &#39;@/components/DatePicker&#39;; import TreeTableLoad from &#39;../components/treeTableLoad.vue&#39;; import SearchForm from &#39;../components/SearchForm.vue&#39;; import MoreSearch from &#39;../components/moreSearch.vue&#39;; import dayjs from &#39;dayjs&#39;; import { getModelListAPI, syncModelInfoAPI, deleteModelAPI } from &#39;@/apis/ptp&#39;; import pinia from &#39;@/store/pinia&#39;; import { useProductMgmtStore } from &#39;@/store/modules/productMgmt&#39;; export default { components: { MyCard, UserTable, Pagination, DatePicker, TreeTableLoad, SearchForm, MoreSearch, }, setup() { const productStore = useProductMgmtStore(pinia); return { productStore, }; }, data() { return { loading: false, searchForm: {}, page: { pageNo: 1, pageSize: 10, }, total: 0, textareas: &#39;&#39;, currentData: {}, searchDate: [], tableData: [], tableWidth: { action: { zh: 160, en: 235 }, }, fixeds: [ { field: &#39;action&#39;, fixed: &#39;right&#39;, }, ], imgAddress: { &#39;sync_status&#39;: { completed: new URL(&#39;../images/Status/completed.png&#39;, import.meta.url).href, error: new URL(&#39;../images/Status/error.png&#39;, import.meta.url).href, waiting: new URL(&#39;../images/Status/waiting.png&#39;, import.meta.url).href, executing: new URL(&#39;../images/Status/executing.png&#39;, import.meta.url).href, }, }, showDialog: false, addTypeDialog: false, showForm: true, }; }, computed: { }, activated() { this.updateResetPage ? this.resetPage() : this.getTableData(); }, created() { window.FURION && window.FURION.reportCustomTime(&#39;rtti&#39;, &#39;1E444AE648FC4C9E9B581B6A35093A05&#39;, 1); this.productStore.setBomCode(&#39;&#39;); }, methods: { expandMore(val) { this.showForm = val; }, // enterSearch(val, flag) { // if (!flag) { // this.$refs.formModel.resetForm(); // this.searchForm = {}; // this.resetPage(); // return; // } // const advancedSearch = this.$refs?.formModel?.formData || {}; // const finalSearch = { // ...advancedSearch, // name_cn: val ? val.trim() : undefined, // }; // this.handleSearchForm(finalSearch); // }, enterSearch(val, flag) { this.searchForm[&#39;name_cn&#39;] = val; if (!flag) { this.$refs.formModel.resetForm(); return; } let search = this.$refs?.formModel?.formData || {}; console.log("search1", search); this.handleSearchForm(search); }, handleSearchForm(search) { console.log("search2", search); this.productStore.setBomCode(search?.bom_code); console.log("this.searchForm", this.searchForm); Object.assign(this.searchForm, search); console.log("this.searchForm2", this.searchForm); console.log("search3", search); this.resetPage(); }, changeDate(val) { this.searchDate = val; this.resetPage(); }, getSearchForm(val) { let search = val || {}; this.handleSearchForm(search); }, resetPage() { this.$refs.Pagination.resetPage(); this.page.pageNo = 1; this.getTableData(); }, tableChange(pageNo, pageSize) { this.page = { pageNo, pageSize, }; this.getTableData(); }, getDateFormat() { let startDate = dayjs(this.searchDate[0]).valueOf(); let endDate = dayjs(`${this.searchDate[1]} 23:59:59`).valueOf(); return { isFuzzy: &#39;N&#39;, value: { $gte: startDate, $lt: endDate, }, }; }, getTableData() { let params = { search: { type: &#39;RD_Model_Info&#39;, &#39;is_valid&#39;: &#39;Y&#39;, ...this.searchForm, &#39;created_by_date&#39;: this.searchDate && this.searchDate.length > 0 ? this.getDateFormat() : &#39;&#39;, }, page: this.page, }; console.log("params",this.params); this.loading = true; getModelListAPI(params) .then(res => { if (res.success && res?.data) { this.tableData = res.data || []; this.total = res.total || 0; } }) .catch(() => { // catch留空 }) .finally(() => { this.loading = false; }); }, closeDialog() { this.currentData = {}; this.textareas = &#39;&#39;; this.showDialog = false; }, deleteData(row) { this.currentData = row; this.showDialog = true; }, submit() { let params = { id: this.currentData.id, reason: this.textareas, }; this.closeDialog(); this.loading = true; deleteModelAPI(params) .then(res => { if (res.success) { this.getTableData(); this.$message.success(this.$t(&#39;actionSuccess&#39;)); } }) .catch(resData => { this.$message.error(resData.message); }) .finally(() => { this.loading = false; }); }, syncData(row) { let params = { &#39;task_type&#39;: &#39;SyncModelTree&#39;, &#39;task_param&#39;: JSON.stringify({ &#39;model_id&#39;: row.id }), &#39;task_name&#39;: row.name_cn, }; this.loading = true; syncModelInfoAPI(params) .then(res => { if (res.success) { this.getTableData(); this.$message.success(this.$t(&#39;同步成功,请到任务管理查看任务进度&#39;)); } }) .catch(resData => { this.$message.error(resData.message); }) .finally(() => { this.loading = false; }); }, add() { this.addTypeDialog = true; }, addModel(val) { this.addTypeDialog = false; const url = { &#39;ILaunch&#39;: &#39;/productMgmt/model/ILaunchModel&#39;, &#39;PDM&#39;: &#39;/productMgmt/model/add&#39;, }; this.$router.push(url[val]); }, edit(row) { let url = row.bom_source === &#39;PDM&#39; ? &#39;/productMgmt/model/edit&#39; : &#39;/productMgmt/model/ILaunchModel&#39;; this.$router.push({ path: url, query: { type: &#39;RD_Model_Info&#39;, id: row.id, }, }); }, viewLog(row) { this.$router.push({ path: &#39;/productMgmt/model/log&#39;, query: { type: &#39;RD_Model_Info&#39;, id: row.id, }, }); }, }, }; </script> <style lang="less" scoped> .content { display: flex; flex-direction: column; height: 100% !important; overflow: auto; padding-bottom: 30px; } .title { display: flex; flex-wrap: nowrap; justify-content: space-between; align-items: center; padding: 0 20px; height: 54px; line-height: 54px; .text { font-size: 16px; color: #252b3a; font-weight: Bold; } } .data_list { flex: 1; margin: 0 20px 20px; } .table_data { margin-top: 20px; } .table_expand { position: sticky; left: 20px; width: 1600px; margin-left: 20px; border-left: 2px solid #5e7ce0; box-shadow: -20px 0 #f2f5fc; } .dialog { .dialog_footer { text-align: center; } } .add_dialog { text-align: center; } </style> 这里打印params为undefined,但是预期应该有输入的search?.bom_code
10-25
提供了基于BP(Back Propagation)神经网络结合PID(比例-积分-微分)控制策略的Simulink仿真模型。该模型旨在实现对杨艺所著论文《基于S函数的BP神经网络PID控制器及Simulink仿真》中的理论进行实践验证。在Matlab 2016b环境下开发,经过测试,确保能够正常运行,适合学习和研究神经网络在控制系统中的应用。 特点 集成BP神经网络:模型中集成了BP神经网络用于提升PID控制器的性能,使之能更好地适应复杂控制环境。 PID控制优化:利用神经网络的自学习能力,对传统的PID控制算法进行了智能调整,提高控制精度和稳定性。 S函数应用:展示了如何在Simulink中通过S函数嵌入MATLAB代码,实现BP神经网络的定制化逻辑。 兼容性说明:虽然开发于Matlab 2016b,但理论上兼容后续版本,可能会需要调整少量配置以适配不同版本的Matlab。 使用指南 环境要求:确保你的电脑上安装有Matlab 2016b或更高版本。 模型加载: 下载本仓库到本地。 在Matlab中打开.slx文件。 运行仿真: 调整模型参数前,请先熟悉各模块功能和输入输出设置。 运行整个模型,观察控制效果。 参数调整: 用户可以自由调节神经网络的层数、节点数以及PID控制器的参数,探索不同的控制性能。 学习和修改: 通过阅读模型中的注释和查阅相关文献,加深对BP神经网络与PID控制结合的理解。 如需修改S函数内的MATLAB代码,建议有一定的MATLAB编程基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值