# Visual Studio安裝工具
* *Web Compiler(SCSS -> CSS) 專案有在使用, 需安裝(或是自行安裝scss->css 的complier) 已把檔案加在jira(http://jira.evervictory-it.com:8080/browse/TKCMS-336)
* AnkhSVN(非必要)
# MVC簡易概要
一開始由Global.asax(後端MVC)當作進入點,
1. 瀏覽器像伺服器發出request
2. IIS接收封包
3. 轉給Route(Global.asax裡面的RegisterRoutes)
4. Route在決定要交給HttpHandler or MVCHandler來處理

專案裡會先由HomeController解析到App.cshtml
然後由於_ViewStart裡面有寫@layout 所以APP.cshtml裡面使用@Renderbody渲染index.cshtml

可參考: https://dotblogs.com.tw/dog0416/2016/06/09/205427
# FE(前端框架帮助文档)
## 框架设计依据
由于BC(博彩)类的web站点的展示形式,如下图所示,一般为一级导航加二级导航,且都是触发某一导航后,替换某一区域内的html片段,故该框架的核心方法为:
``` js
option = {
html: "", //html字符串,如某个<script type="text/html" id="tpl">中的内容
json: "", //服务端取数据地址
param: {}, //请求的参数
bd: $("#div"), //通过模板引擎生成好的html放到一个容器中
... // 其它請直接翻代碼
};
loadModule(option);
```

## 框架文件详解
* `template.js` // 模板引擎
全名ARTtemplate,第三方文件
可參考:https://aui.github.io/art-template/zh-cn/docs/
* `framework-init.js` // 框架核心文件
详细:该文件中产生两个对象,一个是 `Loader` 构造函数,`loadModule` 这个全局方法调用的就是这个构造函数,一个是 `G.util` 的静态方法,用于添加一些常用的静态方法,如生成`guid(G.util.guid)`,编译模板 `G.util.compile`
* `framework-mapping.js` // 框架配置文件
配置每个模块,如导航切换需要用到的html模板地址和从服务端地址,如下
1. 第一種寫法
```javascript
G.map = {
ssc: {
rule: ["/Htmls/ssc/rule.html"],
betdetail: ["/Htmls/betdetail.html", '/Bet/GetBettingSuccess/'],
history: {
history: ["/Htmls/history.html", "/Report/GetBetSummary/", format_history('history')],
date: ["Htmls/history.html", "/Report/GetBetDateSummary/", format_history('date')],
detail: ["Htmls/history.html", "/Report/GetBetDetail/", format_history('detail')]
}
},
pk10: {
...
},
"lottery name": {
"module name": ["template URL", "GET API URL", "callback function"]
}
};
```
2. 第二種寫法
```javascript
G.map = {
betdetail: {
html: {
betdetail: "/Htmls/betdetail.html" //html
},
json: {
betdetail: "/Member/GetMemberBetRecord" // api
},
format: {
betdetail: format_betdetail //api回來的值, 再做處理(Ex: 可能畫面跟資料排序不同等等)
}
},
tema: {
html: {
tema: "/Htmls/playtype/tema.html"
},
json: {
tema: G.action_odds
},
format: {
tema: format_tema
}
}
```
* 设置页面初始需要加载哪个模块
```javascript
G.InitHash = "#!kuaida?pagesize=10";
```
* 设置模板引擎的辅助函数
```javascript
template.helper("format_time", function(){});
```
* 设置 `jquery.validate` 插件一些默认配置
```javascript
$.validator.setDefaults({});
```
* 设置路由的回调函数
```javascript
G.hashFn = {
supper: (function () {
var nav = $("#nav a");
return function (hash_module) {
var module = hash_module.module;
G.util.load({
bd: main,
module: module,
param: hash_module.param || {},
html: hash_module.html,
json: hash_module.json,
hash: hash_module.hash,
refresh: hash_module.refresh
});
nav.removeClass("on").filter("[name=" + module + "]").addClass("on");
}
})()
};
$.each(G.map.ssc, function (module) {
G.hashFn[module] = G.hashFn.supper;
});
```
注意:导航中添加的模块名,需要添加到这里,才会执行模块加载方法。
* `jquery.hashchange.js`
浏览器url hash值变化后,调用hashchange事件,单页面浏览器前进后退时用到,第三方插件,调用已集成到`framework-init.js`中
* `jquery.dialog.js` //弹出框的插件
提供:
` $.alert("text", fn) //提示框 `
` $.confirm("text", fn) //确认框 `
` $.dialog(option) //弹出框 `
弹出框分两种情况:
1. 普通的用法
``` js
$.dialog({
html : "<div>aaa</div>" //html片段
});
```
1. 加载服务器模板
``` js
$.dialog({
module: "" //framework-mapping.js 中配置的 G.map[name]中的name值
html: "" //远程模板地址 G.map[name].html[ name2 ] 中 name2的值
json: "" //远程模板地址 G.map[name].json[ name3 ] 中 name3的值
param: {} //需要用到的参数
});
```
* `jquery.validate.js` //表单验证插件,第三方
```javascript
$("form").validate({
submitHandler: function (form) {
_this.doSave(form);
}
});
```
現多以 `initialize.call(this);` 取代。
* `jquery.tooltip.js` //错误冒泡提示
``` javascript
$("input").tooltip({
html: "这是必填字段" //冒泡显示的内容
isFocus: true 是否获取焦点
isSelect: true 是否选中
});
```
* `module-*.js` 对应模块的业务处理文件
``` javascript
function A (d) {
//该形参 d 为一个Html片段中 `<div name="module" id=’a’></div>` 的元素引用
this.d = d;
}
```
* module-* 玩法的命名規則通常是以拼音為主
Ex: module-tema(tema為特碼拼音)
* `A.prototype.init = function(){}` //模块加载完成后会自动执行 init 方法
* `G.modules[moduleid] = A;` 建立 html 与 js 之间的关联
module id 为 div标签且name="module"的id值
* `module-pager.js` //分页模块
```html
<div name="module" id="pager" class="pager" action="account.account" hash="#!account" format="callback_function_name" param="a=123&b=567">
<select name="pagesize" class="pagesize">
{{pages = [10,20,30,60,100]}}
{{each pages as page}}
<option value="{{page}}" {{if Data.PageSize == page}}selected{{/if}}>{{page}}</option>
{{/each}}
</select>
第 <span class="pageindex red">{{Data.PageIndex}}</span> 页
共 <span class="pagecount red">{{Data.PageCount}}</span> 页
共 <span class="recordcount red">{{Data.RecordCount}}</span> 条
<a href="javascript:void(0)" class="fn-first">首页</a>
<a href="javascript:void(0)" class="fn-prev">上一页</a>
<a href="javascript:void(0)" class="fn-next">下一页</a>
<a href="javascript:void(0)" class="fn-last">尾页</a>
<input type="text" class="input w30 fn-index">
<input type="button" class="btn w30 fn-go" value="GO" />
</div>
```
以上为一段分页 html 代码
當一頁有多個pager的話,記得在module.pager.js最下方多輸出
``` javascript
G.modules.pager = Pager
G.modules.pager2 = Pager
G.modules.pager3 = Pager
G.modules.pager4 = Pager
```
`action: //需要请求的服务器地址`
`pagebody: //需要将分页处理好的html片段放到哪个容器中,值为容器的id`
`template: //需要用到哪个<script type="text/html" id="tpl">中的值作为分页的模板`
`param: //分页需要用到的参数,格式 a=1&b=2`
## 完整url解析
当一个导航加上A链接,如 `href=" #!aaa.bbb|ccc?ddd=1 "`
解析成的格式
``` javascript
loadModule({
module: "aaa",
html: "bbb",
json:"ccc",
param: {ddd : 1}
});
```
當loadModule中有使用到param的話, 對應的html 裡面就可以使用到該資料
例:
module-tema.js
```javasript
loadModule({
module:"aaa",
html: "bbb",
json: "ccc",
param: {ddd : 1}
})
```
bbb.html
```htmlmixed
<div name="module">
<div>
// Param要用大寫P
// Param.ddd = 1
{{Param.ddd}}
</div>
</div>
```
`module-tema.js` //特碼的邏輯代码
先定义一个tema的构造函数
``` javascript
function Tema(d) {
this.d = $(d);
}
```
一些事件绑定添加到其中,其中扩展方法自由发挥,如
``` javascript
Tema.prototype.init = function () {
var _this = this;
this.d.on("click", "#selectAll", function () {
// do something
});
this.d.on("click", ".fn-cancelbet", function () {
_this.cancelBet();
});
}
Tema.prototype.cancelBet = function () {
// do something
};
```
绑定html与js的关联
``` js
G.module.tema = Tema;
* 框架內使用*javascript prototype*的寫法

* 共用模塊
有些module-*.js裡面可能包含不同的html, 使用相同的模組 , 甚至不同的html, 不同的模組
舉例(marksix2 > Scripts > module-tema.js)
```javascript
...
Tema.prototype.destroy = function () {
if (this.id == 'zhengtema') {
doc.triggerHandler("showZheng", [false]);
}
if (this.timer_oddsloop) {
clearInterval(this.timer_oddsloop);
}
};
G.modules.tema = Tema; // 特碼
G.modules.zhengma = Tema; // 正碼
G.modules.zhengtema = Tema; // 正特碼
function QuickBet(d) {
this.d = $(d);
this.UseLastOdds = false;
this.data = [d.json.Param];
}
QuickBet.prototype.init = function () {
initialize.call(this);
this.BetMoney = $("#BetMoney").on("focus", function () {
this.value = G.pre_set ? G.pre_money : this.value;
}).val(G.pre_set ? G.pre_money : this.value).input_digits();
};
...
QuickBet.prototype.doFailBet = function (message) {
var data = {}, param = { "List": this.data };
data.Message = message;
$.extend(data, param);
doc.triggerHandler("betfailed", [data]);
};
G.modules.quickbet = QuickBet;
```
* html、json兩者互相如何傳遞資料?
以六平台為例
```javascript
G.map = {
company: {
html: {
company: "/Htmls/company/company.html",
},
json: {
company: "/Company/GetCompanyList",
}
```
簡單來說,讀取company.html後會打GetCompanyList的api, 然後會進入到在framwork-init.js裡面的Loader, 其中
```javascript
Loader.prototype.getJSON = function(){
var _this = this;
jsonurl = /^\/.+/.test(option.json) ? option.json : option.json ? G.map[option.module].json[option.json] : option.module && !option.html ? G.map[option.module].json[option.module] : null;
if (!jsonurl) {
this.flag += 1;
this.flashHTML(option);
return;
}
G.get({
url: jsonurl,
data: option.param,
success: function (json) {
_this.flag += 1;
_this.jsondata = json; **會把值塞到jsondata裡面**
if (option.jsonSuccess) {
_this.jsondata = option.jsonSuccess(json) || json;
} else {
if (!option.html && !option.json) {
_this.jsondata = G.map[option.module].format && G.map[option.module].format[option.module] ? G.map[option.module].format[option.module](json) || json : json;
} else if (option.module && option.json) {
_this.jsondata = G.map[option.module].format && G.map[option.module].format[option.json] ? G.map[option.module].format[option.json](json) || json : json;
}
}
if(!option.hash || option.hash == G.util.getHash()){
_this.flashHTML(option);
}
},
}
```
最後在Loader.prototype.flashHTML裡的
```javascript
this.jsondata.LoginAccount = LOGIN_ACCOUNT; **其他要共用的東西可參照此寫法
strHTML = G.util.compile(this.template, this.jsondata);
```
再把jsondata跟template compile ,html就會拿到資料
* HTML標籤內驗證
```html=
<input type="text" class="w60 ime-dis" id="pre_money" lessthan="100">
```
lessthan 是設定值小於100,相關設定在framework-mapping.js內
```javascript
$.validator.addMethod("lessthan", function (value, element, param) {
var val = $.trim($(param).val());
val = val ? parseFloat(val) : null;
value = parseFloat(value);
return this.optional(element) || !val || value <= val;
}, "搜索的最小值不能超过最大值!");
```
其他驗證有positive(正數)positivedigits(正整數)nonnegative(非負數)...等